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: (68 commits)
  Input: adp5589-keys - add support for the ADP5585 derivatives
  Input: imx_keypad - add pm suspend and resume support
  Input: force feedback - potential integer wrap in input_ff_create()
  Input: tsc2007 - make sure that X plate resistance is specified
  Input: serio_raw - fix memory leak when closing char device
  Input: serio_raw - kick clients when disconnecting port
  Input: serio_raw - explicitly mark disconnected ports as dead
  Input: serio_raw - fix coding style issues
  Input: serio_raw - use dev_*() for messages
  Input: serio_raw - use bool for boolean data
  Input: serio_raw - perform proper locking when adding clients to list
  Input: serio_raw - rename serio_raw_list to serio_raw_client
  Input: serio_raw - use kref instead of rolling out its own refcounting
  Input: psmouse - switch to using dev_*() for messages
  Input: wacom - correct max Y value on medium bamboos
  Input: wacom - add ABS_DISTANCE to Bamboo Pen reports
  Input: wacom - remove unneeded touch pressure initialization
  Input: lm8323 - wrap suspend and resume in CONFIG_PM_SLEEP
  Input: ad7879-i2c - wrap suspend and resume in CONFIG_PM_SLEEP
  Input: synaptics_i2c - wrap suspend and resume in CONFIG_PM_SLEEP
  ...
This commit is contained in:
Linus Torvalds 2011-10-27 08:44:20 +02:00
commit 396e6e49c5
70 changed files with 4545 additions and 980 deletions

View file

@ -0,0 +1,72 @@
What: /sys/class/hidraw/hidraw*/device/speed
Date: April 2010
Kernel Version: 2.6.35
Contact: linux-bluetooth@vger.kernel.org
Description:
The /sys/class/hidraw/hidraw*/device/speed file controls
reporting speed of Wacom bluetooth tablet. Reading from
this file returns 1 if tablet reports in high speed mode
or 0 otherwise. Writing to this file one of these values
switches reporting speed.
What: /sys/bus/usb/devices/<busnum>-<devnum>:<cfg>.<intf>/wacom_led/led
Date: August 2011
Contact: linux-input@vger.kernel.org
Description:
Attribute group for control of the status LEDs and the OLEDs.
This attribute group is only available for Intuos 4 M, L,
and XL (with LEDs and OLEDs) and Cintiq 21UX2 (LEDs only).
Therefore its presence implicitly signifies the presence of
said LEDs and OLEDs on the tablet device.
What: /sys/bus/usb/devices/<busnum>-<devnum>:<cfg>.<intf>/wacom_led/status0_luminance
Date: August 2011
Contact: linux-input@vger.kernel.org
Description:
Writing to this file sets the status LED luminance (1..127)
when the stylus does not touch the tablet surface, and no
button is pressed on the stylus. This luminance level is
normally lower than the level when a button is pressed.
What: /sys/bus/usb/devices/<busnum>-<devnum>:<cfg>.<intf>/wacom_led/status1_luminance
Date: August 2011
Contact: linux-input@vger.kernel.org
Description:
Writing to this file sets the status LED luminance (1..127)
when the stylus touches the tablet surface, or any button is
pressed on the stylus.
What: /sys/bus/usb/devices/<busnum>-<devnum>:<cfg>.<intf>/wacom_led/status_led0_select
Date: August 2011
Contact: linux-input@vger.kernel.org
Description:
Writing to this file sets which one of the four (for Intuos 4)
or of the right four (for Cintiq 21UX2) status LEDs is active (0..3).
The other three LEDs on the same side are always inactive.
What: /sys/bus/usb/devices/<busnum>-<devnum>:<cfg>.<intf>/wacom_led/status_led1_select
Date: September 2011
Contact: linux-input@vger.kernel.org
Description:
Writing to this file sets which one of the left four (for Cintiq 21UX2)
status LEDs is active (0..3). The other three LEDs on the left are always
inactive.
What: /sys/bus/usb/devices/<busnum>-<devnum>:<cfg>.<intf>/wacom_led/buttons_luminance
Date: August 2011
Contact: linux-input@vger.kernel.org
Description:
Writing to this file sets the overall luminance level (0..15)
of all eight button OLED displays.
What: /sys/bus/usb/devices/<busnum>-<devnum>:<cfg>.<intf>/wacom_led/button<n>_rawimg
Date: August 2011
Contact: linux-input@vger.kernel.org
Description:
When writing a 1024 byte raw image in Wacom Intuos 4
interleaving format to the file, the image shows up on Button N
of the device. The image is a 64x32 pixel 4-bit gray image. The
1024 byte binary is split up into 16x 64 byte chunks. Each 64
byte chunk encodes the image data for two consecutive lines on
the display. The low nibble of each byte contains the first
line, and the high nibble contains the second line.

View file

@ -1,10 +0,0 @@
What: /sys/class/hidraw/hidraw*/device/speed
Date: April 2010
Kernel Version: 2.6.35
Contact: linux-bluetooth@vger.kernel.org
Description:
The /sys/class/hidraw/hidraw*/device/speed file controls
reporting speed of wacom bluetooth tablet. Reading from
this file returns 1 if tablet reports in high speed mode
or 0 otherwise. Writing to this file one of these values
switches reporting speed.

View file

@ -16,15 +16,28 @@ Contents
1. Introduction
2. Extra knobs
3. Hardware version 1
3.1 Registers
3.2 Native relative mode 4 byte packet format
3.3 Native absolute mode 4 byte packet format
4. Hardware version 2
3. Differentiating hardware versions
4. Hardware version 1
4.1 Registers
4.2 Native absolute mode 6 byte packet format
4.2.1 One finger touch
4.2.2 Two finger touch
4.2 Native relative mode 4 byte packet format
4.3 Native absolute mode 4 byte packet format
5. Hardware version 2
5.1 Registers
5.2 Native absolute mode 6 byte packet format
5.2.1 Parity checking and packet re-synchronization
5.2.2 One/Three finger touch
5.2.3 Two finger touch
6. Hardware version 3
6.1 Registers
6.2 Native absolute mode 6 byte packet format
6.2.1 One/Three finger touch
6.2.2 Two finger touch
7. Hardware version 4
7.1 Registers
7.2 Native absolute mode 6 byte packet format
7.2.1 Status packet
7.2.2 Head packet
7.2.3 Motion packet
@ -375,7 +388,7 @@ For all the other ones, there are just a few constant bits:
In case an error is detected, all the packets are shifted by one (and packet[0] is discarded).
5.2.1 One/Three finger touch
5.2.2 One/Three finger touch
~~~~~~~~~~~~~~~~
byte 0:
@ -384,19 +397,19 @@ byte 0:
n1 n0 w3 w2 . . R L
L, R = 1 when Left, Right mouse button pressed
n1..n0 = numbers of fingers on touchpad
n1..n0 = number of fingers on touchpad
byte 1:
bit 7 6 5 4 3 2 1 0
p7 p6 p5 p4 . x10 x9 x8
p7 p6 p5 p4 x11 x10 x9 x8
byte 2:
bit 7 6 5 4 3 2 1 0
x7 x6 x5 x4 x3 x2 x1 x0
x10..x0 = absolute x value (horizontal)
x11..x0 = absolute x value (horizontal)
byte 3:
@ -420,7 +433,7 @@ byte 3:
byte 4:
bit 7 6 5 4 3 2 1 0
p3 p1 p2 p0 . . y9 y8
p3 p1 p2 p0 y11 y10 y9 y8
p7..p0 = pressure (not EF113)
@ -429,10 +442,10 @@ byte 5:
bit 7 6 5 4 3 2 1 0
y7 y6 y5 y4 y3 y2 y1 y0
y9..y0 = absolute y value (vertical)
y11..y0 = absolute y value (vertical)
4.2.2 Two finger touch
5.2.3 Two finger touch
~~~~~~~~~~~~~~~~
Note that the two pairs of coordinates are not exactly the coordinates of the
@ -446,7 +459,7 @@ byte 0:
n1 n0 ay8 ax8 . . R L
L, R = 1 when Left, Right mouse button pressed
n1..n0 = numbers of fingers on touchpad
n1..n0 = number of fingers on touchpad
byte 1:
@ -480,3 +493,253 @@ byte 5:
by7 by8 by5 by4 by3 by2 by1 by0
by8..by0 = upper-right finger absolute y value
/////////////////////////////////////////////////////////////////////////////
6. Hardware version 3
==================
6.1 Registers
~~~~~~~~~
* reg_10
bit 7 6 5 4 3 2 1 0
0 0 0 0 0 0 0 A
A: 1 = enable absolute tracking
6.2 Native absolute mode 6 byte packet format
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1 and 3 finger touch shares the same 6-byte packet format, except that
3 finger touch only reports the position of the center of all three fingers.
Firmware would send 12 bytes of data for 2 finger touch.
Note on debounce:
In case the box has unstable power supply or other electricity issues, or
when number of finger changes, F/W would send "debounce packet" to inform
driver that the hardware is in debounce status.
The debouce packet has the following signature:
byte 0: 0xc4
byte 1: 0xff
byte 2: 0xff
byte 3: 0x02
byte 4: 0xff
byte 5: 0xff
When we encounter this kind of packet, we just ignore it.
6.2.1 One/Three finger touch
~~~~~~~~~~~~~~~~~~~~~~
byte 0:
bit 7 6 5 4 3 2 1 0
n1 n0 w3 w2 0 1 R L
L, R = 1 when Left, Right mouse button pressed
n1..n0 = number of fingers on touchpad
byte 1:
bit 7 6 5 4 3 2 1 0
p7 p6 p5 p4 x11 x10 x9 x8
byte 2:
bit 7 6 5 4 3 2 1 0
x7 x6 x5 x4 x3 x2 x1 x0
x11..x0 = absolute x value (horizontal)
byte 3:
bit 7 6 5 4 3 2 1 0
0 0 w1 w0 0 0 1 0
w3..w0 = width of the finger touch
byte 4:
bit 7 6 5 4 3 2 1 0
p3 p1 p2 p0 y11 y10 y9 y8
p7..p0 = pressure
byte 5:
bit 7 6 5 4 3 2 1 0
y7 y6 y5 y4 y3 y2 y1 y0
y11..y0 = absolute y value (vertical)
6.2.2 Two finger touch
~~~~~~~~~~~~~~~~
The packet format is exactly the same for two finger touch, except the hardware
sends two 6 byte packets. The first packet contains data for the first finger,
the second packet has data for the second finger. So for two finger touch a
total of 12 bytes are sent.
/////////////////////////////////////////////////////////////////////////////
7. Hardware version 4
==================
7.1 Registers
~~~~~~~~~
* reg_07
bit 7 6 5 4 3 2 1 0
0 0 0 0 0 0 0 A
A: 1 = enable absolute tracking
7.2 Native absolute mode 6 byte packet format
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
v4 hardware is a true multitouch touchpad, capable of tracking up to 5 fingers.
Unfortunately, due to PS/2's limited bandwidth, its packet format is rather
complex.
Whenever the numbers or identities of the fingers changes, the hardware sends a
status packet to indicate how many and which fingers is on touchpad, followed by
head packets or motion packets. A head packet contains data of finger id, finger
position (absolute x, y values), width, and pressure. A motion packet contains
two fingers' position delta.
For example, when status packet tells there are 2 fingers on touchpad, then we
can expect two following head packets. If the finger status doesn't change,
the following packets would be motion packets, only sending delta of finger
position, until we receive a status packet.
One exception is one finger touch. when a status packet tells us there is only
one finger, the hardware would just send head packets afterwards.
7.2.1 Status packet
~~~~~~~~~~~~~
byte 0:
bit 7 6 5 4 3 2 1 0
. . . . 0 1 R L
L, R = 1 when Left, Right mouse button pressed
byte 1:
bit 7 6 5 4 3 2 1 0
. . . ft4 ft3 ft2 ft1 ft0
ft4 ft3 ft2 ft1 ft0 ftn = 1 when finger n is on touchpad
byte 2: not used
byte 3:
bit 7 6 5 4 3 2 1 0
. . . 1 0 0 0 0
constant bits
byte 4:
bit 7 6 5 4 3 2 1 0
p . . . . . . .
p = 1 for palm
byte 5: not used
7.2.2 Head packet
~~~~~~~~~~~
byte 0:
bit 7 6 5 4 3 2 1 0
w3 w2 w1 w0 0 1 R L
L, R = 1 when Left, Right mouse button pressed
w3..w0 = finger width (spans how many trace lines)
byte 1:
bit 7 6 5 4 3 2 1 0
p7 p6 p5 p4 x11 x10 x9 x8
byte 2:
bit 7 6 5 4 3 2 1 0
x7 x6 x5 x4 x3 x2 x1 x0
x11..x0 = absolute x value (horizontal)
byte 3:
bit 7 6 5 4 3 2 1 0
id2 id1 id0 1 0 0 0 1
id2..id0 = finger id
byte 4:
bit 7 6 5 4 3 2 1 0
p3 p1 p2 p0 y11 y10 y9 y8
p7..p0 = pressure
byte 5:
bit 7 6 5 4 3 2 1 0
y7 y6 y5 y4 y3 y2 y1 y0
y11..y0 = absolute y value (vertical)
7.2.3 Motion packet
~~~~~~~~~~~~~
byte 0:
bit 7 6 5 4 3 2 1 0
id2 id1 id0 w 0 1 R L
L, R = 1 when Left, Right mouse button pressed
id2..id0 = finger id
w = 1 when delta overflows (> 127 or < -128), in this case
firmware sends us (delta x / 5) and (delta y / 5)
byte 1:
bit 7 6 5 4 3 2 1 0
x7 x6 x5 x4 x3 x2 x1 x0
x7..x0 = delta x (two's complement)
byte 2:
bit 7 6 5 4 3 2 1 0
y7 y6 y5 y4 y3 y2 y1 y0
y7..y0 = delta y (two's complement)
byte 3:
bit 7 6 5 4 3 2 1 0
id2 id1 id0 1 0 0 1 0
id2..id0 = finger id
byte 4:
bit 7 6 5 4 3 2 1 0
x7 x6 x5 x4 x3 x2 x1 x0
x7..x0 = delta x (two's complement)
byte 5:
bit 7 6 5 4 3 2 1 0
y7 y6 y5 y4 y3 y2 y1 y0
y7..y0 = delta y (two's complement)
byte 0 ~ 2 for one finger
byte 3 ~ 5 for another

View file

@ -65,6 +65,20 @@ the full state of each initiated contact has to reside in the receiving
end. Upon receiving an MT event, one simply updates the appropriate
attribute of the current slot.
Some devices identify and/or track more contacts than they can report to the
driver. A driver for such a device should associate one type B slot with each
contact that is reported by the hardware. Whenever the identity of the
contact associated with a slot changes, the driver should invalidate that
slot by changing its ABS_MT_TRACKING_ID. If the hardware signals that it is
tracking more contacts than it is currently reporting, the driver should use
a BTN_TOOL_*TAP event to inform userspace of the total number of contacts
being tracked by the hardware at that moment. The driver should do this by
explicitly sending the corresponding BTN_TOOL_*TAP event and setting
use_count to false when calling input_mt_report_pointer_emulation().
The driver should only advertise as many slots as the hardware can report.
Userspace can detect that a driver can report more total contacts than slots
by noting that the largest supported BTN_TOOL_*TAP event is larger than the
total number of type B slots reported in the absinfo for the ABS_MT_SLOT axis.
Protocol Example A
------------------

View file

@ -309,9 +309,10 @@ EXPORT_SYMBOL_GPL(input_ff_event);
* Once ff device is created you need to setup its upload, erase,
* playback and other handlers before registering input device
*/
int input_ff_create(struct input_dev *dev, int max_effects)
int input_ff_create(struct input_dev *dev, unsigned int max_effects)
{
struct ff_device *ff;
size_t ff_dev_size;
int i;
if (!max_effects) {
@ -319,8 +320,12 @@ int input_ff_create(struct input_dev *dev, int max_effects)
return -EINVAL;
}
ff = kzalloc(sizeof(struct ff_device) +
max_effects * sizeof(struct file *), GFP_KERNEL);
ff_dev_size = sizeof(struct ff_device) +
max_effects * sizeof(struct file *);
if (ff_dev_size < max_effects) /* overflow */
return -EINVAL;
ff = kzalloc(ff_dev_size, GFP_KERNEL);
if (!ff)
return -ENOMEM;

View file

@ -117,6 +117,7 @@ void input_mt_report_finger_count(struct input_dev *dev, int count)
input_event(dev, EV_KEY, BTN_TOOL_DOUBLETAP, count == 2);
input_event(dev, EV_KEY, BTN_TOOL_TRIPLETAP, count == 3);
input_event(dev, EV_KEY, BTN_TOOL_QUADTAP, count == 4);
input_event(dev, EV_KEY, BTN_TOOL_QUINTTAP, count == 5);
}
EXPORT_SYMBOL(input_mt_report_finger_count);

View file

@ -49,8 +49,10 @@ static int input_open_polled_device(struct input_dev *input)
dev->open(dev);
/* Only start polling if polling is enabled */
if (dev->poll_interval > 0)
queue_delayed_work(system_freezable_wq, &dev->work, 0);
if (dev->poll_interval > 0) {
dev->poll(dev);
input_polldev_queue_work(dev);
}
return 0;
}

View file

@ -33,10 +33,10 @@ config KEYBOARD_ADP5588
module will be called adp5588-keys.
config KEYBOARD_ADP5589
tristate "ADP5589 I2C QWERTY Keypad and IO Expander"
tristate "ADP5585/ADP5589 I2C QWERTY Keypad and IO Expander"
depends on I2C
help
Say Y here if you want to use a ADP5589 attached to your
Say Y here if you want to use a ADP5585/ADP5589 attached to your
system I2C bus.
To compile this driver as a module, choose M here: the

View file

@ -550,7 +550,7 @@ static int __devinit adp5588_probe(struct i2c_client *client,
}
error = request_irq(client->irq, adp5588_irq,
IRQF_TRIGGER_FALLING | IRQF_DISABLED,
IRQF_TRIGGER_FALLING,
client->dev.driver->name, kpad);
if (error) {
dev_err(&client->dev, "irq %d busy?\n", client->irq);

View file

@ -1,5 +1,5 @@
/*
* Description: keypad driver for ADP5589
* Description: keypad driver for ADP5589, ADP5585
* I2C QWERTY Keypad and IO Expander
* Bugs: Enter bugs at http://blackfin.uclinux.org/
*
@ -22,35 +22,165 @@
#include <linux/input/adp5589.h>
/* ADP5589/ADP5585 Common Registers */
#define ADP5589_5_ID 0x00
#define ADP5589_5_INT_STATUS 0x01
#define ADP5589_5_STATUS 0x02
#define ADP5589_5_FIFO_1 0x03
#define ADP5589_5_FIFO_2 0x04
#define ADP5589_5_FIFO_3 0x05
#define ADP5589_5_FIFO_4 0x06
#define ADP5589_5_FIFO_5 0x07
#define ADP5589_5_FIFO_6 0x08
#define ADP5589_5_FIFO_7 0x09
#define ADP5589_5_FIFO_8 0x0A
#define ADP5589_5_FIFO_9 0x0B
#define ADP5589_5_FIFO_10 0x0C
#define ADP5589_5_FIFO_11 0x0D
#define ADP5589_5_FIFO_12 0x0E
#define ADP5589_5_FIFO_13 0x0F
#define ADP5589_5_FIFO_14 0x10
#define ADP5589_5_FIFO_15 0x11
#define ADP5589_5_FIFO_16 0x12
#define ADP5589_5_GPI_INT_STAT_A 0x13
#define ADP5589_5_GPI_INT_STAT_B 0x14
/* ADP5589 Registers */
#define ADP5589_GPI_INT_STAT_C 0x15
#define ADP5589_GPI_STATUS_A 0x16
#define ADP5589_GPI_STATUS_B 0x17
#define ADP5589_GPI_STATUS_C 0x18
#define ADP5589_RPULL_CONFIG_A 0x19
#define ADP5589_RPULL_CONFIG_B 0x1A
#define ADP5589_RPULL_CONFIG_C 0x1B
#define ADP5589_RPULL_CONFIG_D 0x1C
#define ADP5589_RPULL_CONFIG_E 0x1D
#define ADP5589_GPI_INT_LEVEL_A 0x1E
#define ADP5589_GPI_INT_LEVEL_B 0x1F
#define ADP5589_GPI_INT_LEVEL_C 0x20
#define ADP5589_GPI_EVENT_EN_A 0x21
#define ADP5589_GPI_EVENT_EN_B 0x22
#define ADP5589_GPI_EVENT_EN_C 0x23
#define ADP5589_GPI_INTERRUPT_EN_A 0x24
#define ADP5589_GPI_INTERRUPT_EN_B 0x25
#define ADP5589_GPI_INTERRUPT_EN_C 0x26
#define ADP5589_DEBOUNCE_DIS_A 0x27
#define ADP5589_DEBOUNCE_DIS_B 0x28
#define ADP5589_DEBOUNCE_DIS_C 0x29
#define ADP5589_GPO_DATA_OUT_A 0x2A
#define ADP5589_GPO_DATA_OUT_B 0x2B
#define ADP5589_GPO_DATA_OUT_C 0x2C
#define ADP5589_GPO_OUT_MODE_A 0x2D
#define ADP5589_GPO_OUT_MODE_B 0x2E
#define ADP5589_GPO_OUT_MODE_C 0x2F
#define ADP5589_GPIO_DIRECTION_A 0x30
#define ADP5589_GPIO_DIRECTION_B 0x31
#define ADP5589_GPIO_DIRECTION_C 0x32
#define ADP5589_UNLOCK1 0x33
#define ADP5589_UNLOCK2 0x34
#define ADP5589_EXT_LOCK_EVENT 0x35
#define ADP5589_UNLOCK_TIMERS 0x36
#define ADP5589_LOCK_CFG 0x37
#define ADP5589_RESET1_EVENT_A 0x38
#define ADP5589_RESET1_EVENT_B 0x39
#define ADP5589_RESET1_EVENT_C 0x3A
#define ADP5589_RESET2_EVENT_A 0x3B
#define ADP5589_RESET2_EVENT_B 0x3C
#define ADP5589_RESET_CFG 0x3D
#define ADP5589_PWM_OFFT_LOW 0x3E
#define ADP5589_PWM_OFFT_HIGH 0x3F
#define ADP5589_PWM_ONT_LOW 0x40
#define ADP5589_PWM_ONT_HIGH 0x41
#define ADP5589_PWM_CFG 0x42
#define ADP5589_CLOCK_DIV_CFG 0x43
#define ADP5589_LOGIC_1_CFG 0x44
#define ADP5589_LOGIC_2_CFG 0x45
#define ADP5589_LOGIC_FF_CFG 0x46
#define ADP5589_LOGIC_INT_EVENT_EN 0x47
#define ADP5589_POLL_PTIME_CFG 0x48
#define ADP5589_PIN_CONFIG_A 0x49
#define ADP5589_PIN_CONFIG_B 0x4A
#define ADP5589_PIN_CONFIG_C 0x4B
#define ADP5589_PIN_CONFIG_D 0x4C
#define ADP5589_GENERAL_CFG 0x4D
#define ADP5589_INT_EN 0x4E
/* ADP5585 Registers */
#define ADP5585_GPI_STATUS_A 0x15
#define ADP5585_GPI_STATUS_B 0x16
#define ADP5585_RPULL_CONFIG_A 0x17
#define ADP5585_RPULL_CONFIG_B 0x18
#define ADP5585_RPULL_CONFIG_C 0x19
#define ADP5585_RPULL_CONFIG_D 0x1A
#define ADP5585_GPI_INT_LEVEL_A 0x1B
#define ADP5585_GPI_INT_LEVEL_B 0x1C
#define ADP5585_GPI_EVENT_EN_A 0x1D
#define ADP5585_GPI_EVENT_EN_B 0x1E
#define ADP5585_GPI_INTERRUPT_EN_A 0x1F
#define ADP5585_GPI_INTERRUPT_EN_B 0x20
#define ADP5585_DEBOUNCE_DIS_A 0x21
#define ADP5585_DEBOUNCE_DIS_B 0x22
#define ADP5585_GPO_DATA_OUT_A 0x23
#define ADP5585_GPO_DATA_OUT_B 0x24
#define ADP5585_GPO_OUT_MODE_A 0x25
#define ADP5585_GPO_OUT_MODE_B 0x26
#define ADP5585_GPIO_DIRECTION_A 0x27
#define ADP5585_GPIO_DIRECTION_B 0x28
#define ADP5585_RESET1_EVENT_A 0x29
#define ADP5585_RESET1_EVENT_B 0x2A
#define ADP5585_RESET1_EVENT_C 0x2B
#define ADP5585_RESET2_EVENT_A 0x2C
#define ADP5585_RESET2_EVENT_B 0x2D
#define ADP5585_RESET_CFG 0x2E
#define ADP5585_PWM_OFFT_LOW 0x2F
#define ADP5585_PWM_OFFT_HIGH 0x30
#define ADP5585_PWM_ONT_LOW 0x31
#define ADP5585_PWM_ONT_HIGH 0x32
#define ADP5585_PWM_CFG 0x33
#define ADP5585_LOGIC_CFG 0x34
#define ADP5585_LOGIC_FF_CFG 0x35
#define ADP5585_LOGIC_INT_EVENT_EN 0x36
#define ADP5585_POLL_PTIME_CFG 0x37
#define ADP5585_PIN_CONFIG_A 0x38
#define ADP5585_PIN_CONFIG_B 0x39
#define ADP5585_PIN_CONFIG_D 0x3A
#define ADP5585_GENERAL_CFG 0x3B
#define ADP5585_INT_EN 0x3C
/* ID Register */
#define ADP5589_5_DEVICE_ID_MASK 0xF
#define ADP5589_5_MAN_ID_MASK 0xF
#define ADP5589_5_MAN_ID_SHIFT 4
#define ADP5589_5_MAN_ID 0x02
/* GENERAL_CFG Register */
#define OSC_EN (1 << 7)
#define CORE_CLK(x) (((x) & 0x3) << 5)
#define LCK_TRK_LOGIC (1 << 4)
#define LCK_TRK_GPI (1 << 3)
#define LCK_TRK_LOGIC (1 << 4) /* ADP5589 only */
#define LCK_TRK_GPI (1 << 3) /* ADP5589 only */
#define INT_CFG (1 << 1)
#define RST_CFG (1 << 0)
/* INT_EN Register */
#define LOGIC2_IEN (1 << 5)
#define LOGIC2_IEN (1 << 5) /* ADP5589 only */
#define LOGIC1_IEN (1 << 4)
#define LOCK_IEN (1 << 3)
#define LOCK_IEN (1 << 3) /* ADP5589 only */
#define OVRFLOW_IEN (1 << 2)
#define GPI_IEN (1 << 1)
#define EVENT_IEN (1 << 0)
/* Interrupt Status Register */
#define LOGIC2_INT (1 << 5)
#define LOGIC2_INT (1 << 5) /* ADP5589 only */
#define LOGIC1_INT (1 << 4)
#define LOCK_INT (1 << 3)
#define LOCK_INT (1 << 3) /* ADP5589 only */
#define OVRFLOW_INT (1 << 2)
#define GPI_INT (1 << 1)
#define EVENT_INT (1 << 0)
/* STATUS Register */
#define LOGIC2_STAT (1 << 7)
#define LOGIC2_STAT (1 << 7) /* ADP5589 only */
#define LOGIC1_STAT (1 << 6)
#define LOCK_STAT (1 << 5)
#define LOCK_STAT (1 << 5) /* ADP5589 only */
#define KEC 0xF
/* PIN_CONFIG_D Register */
@ -61,27 +191,54 @@
#define LOCK_EN (1 << 0)
#define PTIME_MASK 0x3
#define LTIME_MASK 0x3
#define LTIME_MASK 0x3 /* ADP5589 only */
/* Key Event Register xy */
#define KEY_EV_PRESSED (1 << 7)
#define KEY_EV_MASK (0x7F)
#define KEYP_MAX_EVENT 16
#define ADP5589_MAXGPIO 19
#define ADP5585_MAXGPIO 11 /* 10 on the ADP5585-01, 11 on ADP5585-02 */
#define MAXGPIO 19
#define ADP_BANK(offs) ((offs) >> 3)
#define ADP_BIT(offs) (1u << ((offs) & 0x7))
enum {
ADP5589,
ADP5585_01,
ADP5585_02
};
struct adp_constants {
u8 maxgpio;
u8 keymapsize;
u8 gpi_pin_row_base;
u8 gpi_pin_row_end;
u8 gpi_pin_col_base;
u8 gpi_pin_base;
u8 gpi_pin_end;
u8 gpimapsize_max;
u8 max_row_num;
u8 max_col_num;
u8 row_mask;
u8 col_mask;
u8 col_shift;
u8 c4_extend_cfg;
u8 (*bank) (u8 offset);
u8 (*bit) (u8 offset);
u8 (*reg) (u8 reg);
};
struct adp5589_kpad {
struct i2c_client *client;
struct input_dev *input;
const struct adp_constants *var;
unsigned short keycode[ADP5589_KEYMAPSIZE];
const struct adp5589_gpi_map *gpimap;
unsigned short gpimapsize;
unsigned extend_cfg;
bool is_adp5585;
bool adp5585_support_row5;
#ifdef CONFIG_GPIOLIB
unsigned char gpiomap[MAXGPIO];
unsigned char gpiomap[ADP5589_MAXGPIO];
bool export_gpio;
struct gpio_chip gc;
struct mutex gpio_lock; /* Protect cached dir, dat_out */
@ -90,6 +247,129 @@ struct adp5589_kpad {
#endif
};
/*
* ADP5589 / ADP5585 derivative / variant handling
*/
/* ADP5589 */
static unsigned char adp5589_bank(unsigned char offset)
{
return offset >> 3;
}
static unsigned char adp5589_bit(unsigned char offset)
{
return 1u << (offset & 0x7);
}
static unsigned char adp5589_reg(unsigned char reg)
{
return reg;
}
static const struct adp_constants const_adp5589 = {
.maxgpio = ADP5589_MAXGPIO,
.keymapsize = ADP5589_KEYMAPSIZE,
.gpi_pin_row_base = ADP5589_GPI_PIN_ROW_BASE,
.gpi_pin_row_end = ADP5589_GPI_PIN_ROW_END,
.gpi_pin_col_base = ADP5589_GPI_PIN_COL_BASE,
.gpi_pin_base = ADP5589_GPI_PIN_BASE,
.gpi_pin_end = ADP5589_GPI_PIN_END,
.gpimapsize_max = ADP5589_GPIMAPSIZE_MAX,
.c4_extend_cfg = 12,
.max_row_num = ADP5589_MAX_ROW_NUM,
.max_col_num = ADP5589_MAX_COL_NUM,
.row_mask = ADP5589_ROW_MASK,
.col_mask = ADP5589_COL_MASK,
.col_shift = ADP5589_COL_SHIFT,
.bank = adp5589_bank,
.bit = adp5589_bit,
.reg = adp5589_reg,
};
/* ADP5585 */
static unsigned char adp5585_bank(unsigned char offset)
{
return offset > ADP5585_MAX_ROW_NUM;
}
static unsigned char adp5585_bit(unsigned char offset)
{
return (offset > ADP5585_MAX_ROW_NUM) ?
1u << (offset - ADP5585_COL_SHIFT) : 1u << offset;
}
static const unsigned char adp5585_reg_lut[] = {
[ADP5589_GPI_STATUS_A] = ADP5585_GPI_STATUS_A,
[ADP5589_GPI_STATUS_B] = ADP5585_GPI_STATUS_B,
[ADP5589_RPULL_CONFIG_A] = ADP5585_RPULL_CONFIG_A,
[ADP5589_RPULL_CONFIG_B] = ADP5585_RPULL_CONFIG_B,
[ADP5589_RPULL_CONFIG_C] = ADP5585_RPULL_CONFIG_C,
[ADP5589_RPULL_CONFIG_D] = ADP5585_RPULL_CONFIG_D,
[ADP5589_GPI_INT_LEVEL_A] = ADP5585_GPI_INT_LEVEL_A,
[ADP5589_GPI_INT_LEVEL_B] = ADP5585_GPI_INT_LEVEL_B,
[ADP5589_GPI_EVENT_EN_A] = ADP5585_GPI_EVENT_EN_A,
[ADP5589_GPI_EVENT_EN_B] = ADP5585_GPI_EVENT_EN_B,
[ADP5589_GPI_INTERRUPT_EN_A] = ADP5585_GPI_INTERRUPT_EN_A,
[ADP5589_GPI_INTERRUPT_EN_B] = ADP5585_GPI_INTERRUPT_EN_B,
[ADP5589_DEBOUNCE_DIS_A] = ADP5585_DEBOUNCE_DIS_A,
[ADP5589_DEBOUNCE_DIS_B] = ADP5585_DEBOUNCE_DIS_B,
[ADP5589_GPO_DATA_OUT_A] = ADP5585_GPO_DATA_OUT_A,
[ADP5589_GPO_DATA_OUT_B] = ADP5585_GPO_DATA_OUT_B,
[ADP5589_GPO_OUT_MODE_A] = ADP5585_GPO_OUT_MODE_A,
[ADP5589_GPO_OUT_MODE_B] = ADP5585_GPO_OUT_MODE_B,
[ADP5589_GPIO_DIRECTION_A] = ADP5585_GPIO_DIRECTION_A,
[ADP5589_GPIO_DIRECTION_B] = ADP5585_GPIO_DIRECTION_B,
[ADP5589_RESET1_EVENT_A] = ADP5585_RESET1_EVENT_A,
[ADP5589_RESET1_EVENT_B] = ADP5585_RESET1_EVENT_B,
[ADP5589_RESET1_EVENT_C] = ADP5585_RESET1_EVENT_C,
[ADP5589_RESET2_EVENT_A] = ADP5585_RESET2_EVENT_A,
[ADP5589_RESET2_EVENT_B] = ADP5585_RESET2_EVENT_B,
[ADP5589_RESET_CFG] = ADP5585_RESET_CFG,
[ADP5589_PWM_OFFT_LOW] = ADP5585_PWM_OFFT_LOW,
[ADP5589_PWM_OFFT_HIGH] = ADP5585_PWM_OFFT_HIGH,
[ADP5589_PWM_ONT_LOW] = ADP5585_PWM_ONT_LOW,
[ADP5589_PWM_ONT_HIGH] = ADP5585_PWM_ONT_HIGH,
[ADP5589_PWM_CFG] = ADP5585_PWM_CFG,
[ADP5589_LOGIC_1_CFG] = ADP5585_LOGIC_CFG,
[ADP5589_LOGIC_FF_CFG] = ADP5585_LOGIC_FF_CFG,
[ADP5589_LOGIC_INT_EVENT_EN] = ADP5585_LOGIC_INT_EVENT_EN,
[ADP5589_POLL_PTIME_CFG] = ADP5585_POLL_PTIME_CFG,
[ADP5589_PIN_CONFIG_A] = ADP5585_PIN_CONFIG_A,
[ADP5589_PIN_CONFIG_B] = ADP5585_PIN_CONFIG_B,
[ADP5589_PIN_CONFIG_D] = ADP5585_PIN_CONFIG_D,
[ADP5589_GENERAL_CFG] = ADP5585_GENERAL_CFG,
[ADP5589_INT_EN] = ADP5585_INT_EN,
};
static unsigned char adp5585_reg(unsigned char reg)
{
return adp5585_reg_lut[reg];
}
static const struct adp_constants const_adp5585 = {
.maxgpio = ADP5585_MAXGPIO,
.keymapsize = ADP5585_KEYMAPSIZE,
.gpi_pin_row_base = ADP5585_GPI_PIN_ROW_BASE,
.gpi_pin_row_end = ADP5585_GPI_PIN_ROW_END,
.gpi_pin_col_base = ADP5585_GPI_PIN_COL_BASE,
.gpi_pin_base = ADP5585_GPI_PIN_BASE,
.gpi_pin_end = ADP5585_GPI_PIN_END,
.gpimapsize_max = ADP5585_GPIMAPSIZE_MAX,
.c4_extend_cfg = 10,
.max_row_num = ADP5585_MAX_ROW_NUM,
.max_col_num = ADP5585_MAX_COL_NUM,
.row_mask = ADP5585_ROW_MASK,
.col_mask = ADP5585_COL_MASK,
.col_shift = ADP5585_COL_SHIFT,
.bank = adp5585_bank,
.bit = adp5585_bit,
.reg = adp5585_reg,
};
static int adp5589_read(struct i2c_client *client, u8 reg)
{
int ret = i2c_smbus_read_byte_data(client, reg);
@ -109,19 +389,20 @@ static int adp5589_write(struct i2c_client *client, u8 reg, u8 val)
static int adp5589_gpio_get_value(struct gpio_chip *chip, unsigned off)
{
struct adp5589_kpad *kpad = container_of(chip, struct adp5589_kpad, gc);
unsigned int bank = ADP_BANK(kpad->gpiomap[off]);
unsigned int bit = ADP_BIT(kpad->gpiomap[off]);
unsigned int bank = kpad->var->bank(kpad->gpiomap[off]);
unsigned int bit = kpad->var->bit(kpad->gpiomap[off]);
return !!(adp5589_read(kpad->client, ADP5589_GPI_STATUS_A + bank) &
bit);
return !!(adp5589_read(kpad->client,
kpad->var->reg(ADP5589_GPI_STATUS_A) + bank) &
bit);
}
static void adp5589_gpio_set_value(struct gpio_chip *chip,
unsigned off, int val)
{
struct adp5589_kpad *kpad = container_of(chip, struct adp5589_kpad, gc);
unsigned int bank = ADP_BANK(kpad->gpiomap[off]);
unsigned int bit = ADP_BIT(kpad->gpiomap[off]);
unsigned int bank = kpad->var->bank(kpad->gpiomap[off]);
unsigned int bit = kpad->var->bit(kpad->gpiomap[off]);
mutex_lock(&kpad->gpio_lock);
@ -130,8 +411,8 @@ static void adp5589_gpio_set_value(struct gpio_chip *chip,
else
kpad->dat_out[bank] &= ~bit;
adp5589_write(kpad->client, ADP5589_GPO_DATA_OUT_A + bank,
kpad->dat_out[bank]);
adp5589_write(kpad->client, kpad->var->reg(ADP5589_GPO_DATA_OUT_A) +
bank, kpad->dat_out[bank]);
mutex_unlock(&kpad->gpio_lock);
}
@ -139,14 +420,15 @@ static void adp5589_gpio_set_value(struct gpio_chip *chip,
static int adp5589_gpio_direction_input(struct gpio_chip *chip, unsigned off)
{
struct adp5589_kpad *kpad = container_of(chip, struct adp5589_kpad, gc);
unsigned int bank = ADP_BANK(kpad->gpiomap[off]);
unsigned int bit = ADP_BIT(kpad->gpiomap[off]);
unsigned int bank = kpad->var->bank(kpad->gpiomap[off]);
unsigned int bit = kpad->var->bit(kpad->gpiomap[off]);
int ret;
mutex_lock(&kpad->gpio_lock);
kpad->dir[bank] &= ~bit;
ret = adp5589_write(kpad->client, ADP5589_GPIO_DIRECTION_A + bank,
ret = adp5589_write(kpad->client,
kpad->var->reg(ADP5589_GPIO_DIRECTION_A) + bank,
kpad->dir[bank]);
mutex_unlock(&kpad->gpio_lock);
@ -158,8 +440,8 @@ static int adp5589_gpio_direction_output(struct gpio_chip *chip,
unsigned off, int val)
{
struct adp5589_kpad *kpad = container_of(chip, struct adp5589_kpad, gc);
unsigned int bank = ADP_BANK(kpad->gpiomap[off]);
unsigned int bit = ADP_BIT(kpad->gpiomap[off]);
unsigned int bank = kpad->var->bank(kpad->gpiomap[off]);
unsigned int bit = kpad->var->bit(kpad->gpiomap[off]);
int ret;
mutex_lock(&kpad->gpio_lock);
@ -171,9 +453,10 @@ static int adp5589_gpio_direction_output(struct gpio_chip *chip,
else
kpad->dat_out[bank] &= ~bit;
ret = adp5589_write(kpad->client, ADP5589_GPO_DATA_OUT_A + bank,
kpad->dat_out[bank]);
ret |= adp5589_write(kpad->client, ADP5589_GPIO_DIRECTION_A + bank,
ret = adp5589_write(kpad->client, kpad->var->reg(ADP5589_GPO_DATA_OUT_A)
+ bank, kpad->dat_out[bank]);
ret |= adp5589_write(kpad->client,
kpad->var->reg(ADP5589_GPIO_DIRECTION_A) + bank,
kpad->dir[bank]);
mutex_unlock(&kpad->gpio_lock);
@ -184,26 +467,29 @@ static int adp5589_gpio_direction_output(struct gpio_chip *chip,
static int __devinit adp5589_build_gpiomap(struct adp5589_kpad *kpad,
const struct adp5589_kpad_platform_data *pdata)
{
bool pin_used[MAXGPIO];
bool pin_used[ADP5589_MAXGPIO];
int n_unused = 0;
int i;
memset(pin_used, false, sizeof(pin_used));
for (i = 0; i < MAXGPIO; i++)
for (i = 0; i < kpad->var->maxgpio; i++)
if (pdata->keypad_en_mask & (1 << i))
pin_used[i] = true;
for (i = 0; i < kpad->gpimapsize; i++)
pin_used[kpad->gpimap[i].pin - ADP5589_GPI_PIN_BASE] = true;
pin_used[kpad->gpimap[i].pin - kpad->var->gpi_pin_base] = true;
if (kpad->extend_cfg & R4_EXTEND_CFG)
pin_used[4] = true;
if (kpad->extend_cfg & C4_EXTEND_CFG)
pin_used[12] = true;
pin_used[kpad->var->c4_extend_cfg] = true;
for (i = 0; i < MAXGPIO; i++)
if (!kpad->adp5585_support_row5)
pin_used[5] = true;
for (i = 0; i < kpad->var->maxgpio; i++)
if (!pin_used[i])
kpad->gpiomap[n_unused++] = i;
@ -246,11 +532,11 @@ static int __devinit adp5589_gpio_add(struct adp5589_kpad *kpad)
return error;
}
for (i = 0; i <= ADP_BANK(MAXGPIO); i++) {
kpad->dat_out[i] = adp5589_read(kpad->client,
ADP5589_GPO_DATA_OUT_A + i);
kpad->dir[i] = adp5589_read(kpad->client,
ADP5589_GPIO_DIRECTION_A + i);
for (i = 0; i <= kpad->var->bank(kpad->var->maxgpio); i++) {
kpad->dat_out[i] = adp5589_read(kpad->client, kpad->var->reg(
ADP5589_GPO_DATA_OUT_A) + i);
kpad->dir[i] = adp5589_read(kpad->client, kpad->var->reg(
ADP5589_GPIO_DIRECTION_A) + i);
}
if (gpio_data->setup) {
@ -317,11 +603,11 @@ static void adp5589_report_events(struct adp5589_kpad *kpad, int ev_cnt)
int i;
for (i = 0; i < ev_cnt; i++) {
int key = adp5589_read(kpad->client, ADP5589_FIFO_1 + i);
int key = adp5589_read(kpad->client, ADP5589_5_FIFO_1 + i);
int key_val = key & KEY_EV_MASK;
if (key_val >= ADP5589_GPI_PIN_BASE &&
key_val <= ADP5589_GPI_PIN_END) {
if (key_val >= kpad->var->gpi_pin_base &&
key_val <= kpad->var->gpi_pin_end) {
adp5589_report_switches(kpad, key, key_val);
} else {
input_report_key(kpad->input,
@ -337,29 +623,30 @@ static irqreturn_t adp5589_irq(int irq, void *handle)
struct i2c_client *client = kpad->client;
int status, ev_cnt;
status = adp5589_read(client, ADP5589_INT_STATUS);
status = adp5589_read(client, ADP5589_5_INT_STATUS);
if (status & OVRFLOW_INT) /* Unlikely and should never happen */
dev_err(&client->dev, "Event Overflow Error\n");
if (status & EVENT_INT) {
ev_cnt = adp5589_read(client, ADP5589_STATUS) & KEC;
ev_cnt = adp5589_read(client, ADP5589_5_STATUS) & KEC;
if (ev_cnt) {
adp5589_report_events(kpad, ev_cnt);
input_sync(kpad->input);
}
}
adp5589_write(client, ADP5589_INT_STATUS, status); /* Status is W1C */
adp5589_write(client, ADP5589_5_INT_STATUS, status); /* Status is W1C */
return IRQ_HANDLED;
}
static int __devinit adp5589_get_evcode(struct adp5589_kpad *kpad, unsigned short key)
static int __devinit adp5589_get_evcode(struct adp5589_kpad *kpad,
unsigned short key)
{
int i;
for (i = 0; i < ADP5589_KEYMAPSIZE; i++)
for (i = 0; i < kpad->var->keymapsize; i++)
if (key == kpad->keycode[i])
return (i + 1) | KEY_EV_PRESSED;
@ -372,19 +659,23 @@ static int __devinit adp5589_setup(struct adp5589_kpad *kpad)
{
struct i2c_client *client = kpad->client;
const struct adp5589_kpad_platform_data *pdata =
client->dev.platform_data;
int i, ret;
client->dev.platform_data;
u8 (*reg) (u8) = kpad->var->reg;
unsigned char evt_mode1 = 0, evt_mode2 = 0, evt_mode3 = 0;
unsigned char pull_mask = 0;
int i, ret;
ret = adp5589_write(client, ADP5589_PIN_CONFIG_A,
pdata->keypad_en_mask & 0xFF);
ret |= adp5589_write(client, ADP5589_PIN_CONFIG_B,
(pdata->keypad_en_mask >> 8) & 0xFF);
ret |= adp5589_write(client, ADP5589_PIN_CONFIG_C,
(pdata->keypad_en_mask >> 16) & 0xFF);
ret = adp5589_write(client, reg(ADP5589_PIN_CONFIG_A),
pdata->keypad_en_mask & kpad->var->row_mask);
ret |= adp5589_write(client, reg(ADP5589_PIN_CONFIG_B),
(pdata->keypad_en_mask >> kpad->var->col_shift) &
kpad->var->col_mask);
if (pdata->en_keylock) {
if (!kpad->is_adp5585)
ret |= adp5589_write(client, ADP5589_PIN_CONFIG_C,
(pdata->keypad_en_mask >> 16) & 0xFF);
if (!kpad->is_adp5585 && pdata->en_keylock) {
ret |= adp5589_write(client, ADP5589_UNLOCK1,
pdata->unlock_key1);
ret |= adp5589_write(client, ADP5589_UNLOCK2,
@ -395,96 +686,130 @@ static int __devinit adp5589_setup(struct adp5589_kpad *kpad)
}
for (i = 0; i < KEYP_MAX_EVENT; i++)
ret |= adp5589_read(client, ADP5589_FIFO_1 + i);
ret |= adp5589_read(client, ADP5589_5_FIFO_1 + i);
for (i = 0; i < pdata->gpimapsize; i++) {
unsigned short pin = pdata->gpimap[i].pin;
if (pin <= ADP5589_GPI_PIN_ROW_END) {
evt_mode1 |= (1 << (pin - ADP5589_GPI_PIN_ROW_BASE));
if (pin <= kpad->var->gpi_pin_row_end) {
evt_mode1 |= (1 << (pin - kpad->var->gpi_pin_row_base));
} else {
evt_mode2 |=
((1 << (pin - ADP5589_GPI_PIN_COL_BASE)) & 0xFF);
evt_mode3 |=
((1 << (pin - ADP5589_GPI_PIN_COL_BASE)) >> 8);
((1 << (pin - kpad->var->gpi_pin_col_base)) & 0xFF);
if (!kpad->is_adp5585)
evt_mode3 |= ((1 << (pin -
kpad->var->gpi_pin_col_base)) >> 8);
}
}
if (pdata->gpimapsize) {
ret |= adp5589_write(client, ADP5589_GPI_EVENT_EN_A, evt_mode1);
ret |= adp5589_write(client, ADP5589_GPI_EVENT_EN_B, evt_mode2);
ret |= adp5589_write(client, ADP5589_GPI_EVENT_EN_C, evt_mode3);
ret |= adp5589_write(client, reg(ADP5589_GPI_EVENT_EN_A),
evt_mode1);
ret |= adp5589_write(client, reg(ADP5589_GPI_EVENT_EN_B),
evt_mode2);
if (!kpad->is_adp5585)
ret |= adp5589_write(client,
reg(ADP5589_GPI_EVENT_EN_C),
evt_mode3);
}
if (pdata->pull_dis_mask & pdata->pullup_en_100k &
pdata->pullup_en_300k & pdata->pulldown_en_300k)
pdata->pullup_en_300k & pdata->pulldown_en_300k)
dev_warn(&client->dev, "Conflicting pull resistor config\n");
for (i = 0; i < MAXGPIO; i++) {
unsigned val = 0;
if (pdata->pullup_en_300k & (1 << i))
for (i = 0; i <= kpad->var->max_row_num; i++) {
unsigned val = 0, bit = (1 << i);
if (pdata->pullup_en_300k & bit)
val = 0;
else if (pdata->pulldown_en_300k & (1 << i))
else if (pdata->pulldown_en_300k & bit)
val = 1;
else if (pdata->pullup_en_100k & (1 << i))
else if (pdata->pullup_en_100k & bit)
val = 2;
else if (pdata->pull_dis_mask & (1 << i))
else if (pdata->pull_dis_mask & bit)
val = 3;
pull_mask |= val << (2 * (i & 0x3));
if ((i & 0x3) == 0x3 || i == MAXGPIO - 1) {
if (i == 3 || i == kpad->var->max_row_num) {
ret |= adp5589_write(client, reg(ADP5585_RPULL_CONFIG_A)
+ (i >> 2), pull_mask);
pull_mask = 0;
}
}
for (i = 0; i <= kpad->var->max_col_num; i++) {
unsigned val = 0, bit = 1 << (i + kpad->var->col_shift);
if (pdata->pullup_en_300k & bit)
val = 0;
else if (pdata->pulldown_en_300k & bit)
val = 1;
else if (pdata->pullup_en_100k & bit)
val = 2;
else if (pdata->pull_dis_mask & bit)
val = 3;
pull_mask |= val << (2 * (i & 0x3));
if (i == 3 || i == kpad->var->max_col_num) {
ret |= adp5589_write(client,
ADP5589_RPULL_CONFIG_A + (i >> 2),
pull_mask);
reg(ADP5585_RPULL_CONFIG_C) +
(i >> 2), pull_mask);
pull_mask = 0;
}
}
if (pdata->reset1_key_1 && pdata->reset1_key_2 && pdata->reset1_key_3) {
ret |= adp5589_write(client, ADP5589_RESET1_EVENT_A,
ret |= adp5589_write(client, reg(ADP5589_RESET1_EVENT_A),
adp5589_get_evcode(kpad,
pdata->reset1_key_1));
ret |= adp5589_write(client, ADP5589_RESET1_EVENT_B,
ret |= adp5589_write(client, reg(ADP5589_RESET1_EVENT_B),
adp5589_get_evcode(kpad,
pdata->reset1_key_2));
ret |= adp5589_write(client, ADP5589_RESET1_EVENT_C,
ret |= adp5589_write(client, reg(ADP5589_RESET1_EVENT_C),
adp5589_get_evcode(kpad,
pdata->reset1_key_3));
kpad->extend_cfg |= R4_EXTEND_CFG;
}
if (pdata->reset2_key_1 && pdata->reset2_key_2) {
ret |= adp5589_write(client, ADP5589_RESET2_EVENT_A,
ret |= adp5589_write(client, reg(ADP5589_RESET2_EVENT_A),
adp5589_get_evcode(kpad,
pdata->reset2_key_1));
ret |= adp5589_write(client, ADP5589_RESET2_EVENT_B,
ret |= adp5589_write(client, reg(ADP5589_RESET2_EVENT_B),
adp5589_get_evcode(kpad,
pdata->reset2_key_2));
kpad->extend_cfg |= C4_EXTEND_CFG;
}
if (kpad->extend_cfg) {
ret |= adp5589_write(client, ADP5589_RESET_CFG,
ret |= adp5589_write(client, reg(ADP5589_RESET_CFG),
pdata->reset_cfg);
ret |= adp5589_write(client, ADP5589_PIN_CONFIG_D,
ret |= adp5589_write(client, reg(ADP5589_PIN_CONFIG_D),
kpad->extend_cfg);
}
for (i = 0; i <= ADP_BANK(MAXGPIO); i++)
ret |= adp5589_write(client, ADP5589_DEBOUNCE_DIS_A + i,
pdata->debounce_dis_mask >> (i * 8));
ret |= adp5589_write(client, reg(ADP5589_DEBOUNCE_DIS_A),
pdata->debounce_dis_mask & kpad->var->row_mask);
ret |= adp5589_write(client, ADP5589_POLL_PTIME_CFG,
ret |= adp5589_write(client, reg(ADP5589_DEBOUNCE_DIS_B),
(pdata->debounce_dis_mask >> kpad->var->col_shift)
& kpad->var->col_mask);
if (!kpad->is_adp5585)
ret |= adp5589_write(client, reg(ADP5589_DEBOUNCE_DIS_C),
(pdata->debounce_dis_mask >> 16) & 0xFF);
ret |= adp5589_write(client, reg(ADP5589_POLL_PTIME_CFG),
pdata->scan_cycle_time & PTIME_MASK);
ret |= adp5589_write(client, ADP5589_INT_STATUS, LOGIC2_INT |
LOGIC1_INT | OVRFLOW_INT | LOCK_INT |
ret |= adp5589_write(client, ADP5589_5_INT_STATUS,
(kpad->is_adp5585 ? 0 : LOGIC2_INT) |
LOGIC1_INT | OVRFLOW_INT |
(kpad->is_adp5585 ? 0 : LOCK_INT) |
GPI_INT | EVENT_INT); /* Status is W1C */
ret |= adp5589_write(client, ADP5589_GENERAL_CFG,
ret |= adp5589_write(client, reg(ADP5589_GENERAL_CFG),
INT_CFG | OSC_EN | CORE_CLK(3));
ret |= adp5589_write(client, ADP5589_INT_EN,
ret |= adp5589_write(client, reg(ADP5589_INT_EN),
OVRFLOW_IEN | GPI_IEN | EVENT_IEN);
if (ret < 0) {
@ -497,30 +822,33 @@ static int __devinit adp5589_setup(struct adp5589_kpad *kpad)
static void __devinit adp5589_report_switch_state(struct adp5589_kpad *kpad)
{
int gpi_stat1 = adp5589_read(kpad->client, ADP5589_GPI_STATUS_A);
int gpi_stat2 = adp5589_read(kpad->client, ADP5589_GPI_STATUS_B);
int gpi_stat3 = adp5589_read(kpad->client, ADP5589_GPI_STATUS_C);
int gpi_stat_tmp, pin_loc;
int i;
int gpi_stat1 = adp5589_read(kpad->client,
kpad->var->reg(ADP5589_GPI_STATUS_A));
int gpi_stat2 = adp5589_read(kpad->client,
kpad->var->reg(ADP5589_GPI_STATUS_B));
int gpi_stat3 = !kpad->is_adp5585 ?
adp5589_read(kpad->client, ADP5589_GPI_STATUS_C) : 0;
for (i = 0; i < kpad->gpimapsize; i++) {
unsigned short pin = kpad->gpimap[i].pin;
if (pin <= ADP5589_GPI_PIN_ROW_END) {
if (pin <= kpad->var->gpi_pin_row_end) {
gpi_stat_tmp = gpi_stat1;
pin_loc = pin - ADP5589_GPI_PIN_ROW_BASE;
} else if ((pin - ADP5589_GPI_PIN_COL_BASE) < 8) {
pin_loc = pin - kpad->var->gpi_pin_row_base;
} else if ((pin - kpad->var->gpi_pin_col_base) < 8) {
gpi_stat_tmp = gpi_stat2;
pin_loc = pin - ADP5589_GPI_PIN_COL_BASE;
pin_loc = pin - kpad->var->gpi_pin_col_base;
} else {
gpi_stat_tmp = gpi_stat3;
pin_loc = pin - ADP5589_GPI_PIN_COL_BASE - 8;
pin_loc = pin - kpad->var->gpi_pin_col_base - 8;
}
if (gpi_stat_tmp < 0) {
dev_err(&kpad->client->dev,
"Can't read GPIO_DAT_STAT switch"
" %d default to OFF\n", pin);
"Can't read GPIO_DAT_STAT switch %d, default to OFF\n",
pin);
gpi_stat_tmp = 0;
}
@ -536,7 +864,8 @@ static int __devinit adp5589_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct adp5589_kpad *kpad;
const struct adp5589_kpad_platform_data *pdata;
const struct adp5589_kpad_platform_data *pdata =
client->dev.platform_data;
struct input_dev *input;
unsigned int revid;
int ret, i;
@ -548,56 +877,79 @@ static int __devinit adp5589_probe(struct i2c_client *client,
return -EIO;
}
pdata = client->dev.platform_data;
if (!pdata) {
dev_err(&client->dev, "no platform data?\n");
return -EINVAL;
}
if (!((pdata->keypad_en_mask & 0xFF) &&
(pdata->keypad_en_mask >> 8)) || !pdata->keymap) {
dev_err(&client->dev, "no rows, cols or keymap from pdata\n");
return -EINVAL;
kpad = kzalloc(sizeof(*kpad), GFP_KERNEL);
if (!kpad)
return -ENOMEM;
switch (id->driver_data) {
case ADP5585_02:
kpad->adp5585_support_row5 = true;
case ADP5585_01:
kpad->is_adp5585 = true;
kpad->var = &const_adp5585;
break;
case ADP5589:
kpad->var = &const_adp5589;
break;
}
if (pdata->keymapsize != ADP5589_KEYMAPSIZE) {
if (!((pdata->keypad_en_mask & kpad->var->row_mask) &&
(pdata->keypad_en_mask >> kpad->var->col_shift)) ||
!pdata->keymap) {
dev_err(&client->dev, "no rows, cols or keymap from pdata\n");
error = -EINVAL;
goto err_free_mem;
}
if (pdata->keymapsize != kpad->var->keymapsize) {
dev_err(&client->dev, "invalid keymapsize\n");
return -EINVAL;
error = -EINVAL;
goto err_free_mem;
}
if (!pdata->gpimap && pdata->gpimapsize) {
dev_err(&client->dev, "invalid gpimap from pdata\n");
return -EINVAL;
error = -EINVAL;
goto err_free_mem;
}
if (pdata->gpimapsize > ADP5589_GPIMAPSIZE_MAX) {
if (pdata->gpimapsize > kpad->var->gpimapsize_max) {
dev_err(&client->dev, "invalid gpimapsize\n");
return -EINVAL;
error = -EINVAL;
goto err_free_mem;
}
for (i = 0; i < pdata->gpimapsize; i++) {
unsigned short pin = pdata->gpimap[i].pin;
if (pin < ADP5589_GPI_PIN_BASE || pin > ADP5589_GPI_PIN_END) {
if (pin < kpad->var->gpi_pin_base ||
pin > kpad->var->gpi_pin_end) {
dev_err(&client->dev, "invalid gpi pin data\n");
return -EINVAL;
error = -EINVAL;
goto err_free_mem;
}
if ((1 << (pin - ADP5589_GPI_PIN_ROW_BASE)) &
if ((1 << (pin - kpad->var->gpi_pin_row_base)) &
pdata->keypad_en_mask) {
dev_err(&client->dev, "invalid gpi row/col data\n");
return -EINVAL;
error = -EINVAL;
goto err_free_mem;
}
}
if (!client->irq) {
dev_err(&client->dev, "no IRQ?\n");
return -EINVAL;
error = -EINVAL;
goto err_free_mem;
}
kpad = kzalloc(sizeof(*kpad), GFP_KERNEL);
input = input_allocate_device();
if (!kpad || !input) {
if (!input) {
error = -ENOMEM;
goto err_free_mem;
}
@ -605,13 +957,13 @@ static int __devinit adp5589_probe(struct i2c_client *client,
kpad->client = client;
kpad->input = input;
ret = adp5589_read(client, ADP5589_ID);
ret = adp5589_read(client, ADP5589_5_ID);
if (ret < 0) {
error = ret;
goto err_free_mem;
goto err_free_input;
}
revid = (u8) ret & ADP5589_DEVICE_ID_MASK;
revid = (u8) ret & ADP5589_5_DEVICE_ID_MASK;
input->name = client->name;
input->phys = "adp5589-keys/input0";
@ -652,7 +1004,7 @@ static int __devinit adp5589_probe(struct i2c_client *client,
error = input_register_device(input);
if (error) {
dev_err(&client->dev, "unable to register input device\n");
goto err_free_mem;
goto err_free_input;
}
error = request_threaded_irq(client->irq, NULL, adp5589_irq,
@ -685,8 +1037,9 @@ static int __devinit adp5589_probe(struct i2c_client *client,
err_unreg_dev:
input_unregister_device(input);
input = NULL;
err_free_mem:
err_free_input:
input_free_device(input);
err_free_mem:
kfree(kpad);
return error;
@ -696,7 +1049,7 @@ static int __devexit adp5589_remove(struct i2c_client *client)
{
struct adp5589_kpad *kpad = i2c_get_clientdata(client);
adp5589_write(client, ADP5589_GENERAL_CFG, 0);
adp5589_write(client, kpad->var->reg(ADP5589_GENERAL_CFG), 0);
free_irq(client->irq, kpad);
input_unregister_device(kpad->input);
adp5589_gpio_remove(kpad);
@ -736,7 +1089,9 @@ static int adp5589_resume(struct device *dev)
static SIMPLE_DEV_PM_OPS(adp5589_dev_pm_ops, adp5589_suspend, adp5589_resume);
static const struct i2c_device_id adp5589_id[] = {
{"adp5589-keys", 0},
{"adp5589-keys", ADP5589},
{"adp5585-keys", ADP5585_01},
{"adp5585-02-keys", ADP5585_02}, /* Adds ROW5 to ADP5585 */
{}
};
@ -767,4 +1122,4 @@ module_exit(adp5589_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
MODULE_DESCRIPTION("ADP5589 Keypad driver");
MODULE_DESCRIPTION("ADP5589/ADP5585 Keypad driver");

View file

@ -271,7 +271,7 @@ static int __init davinci_ks_probe(struct platform_device *pdev)
}
error = request_irq(davinci_ks->irq, davinci_ks_interrupt,
IRQF_DISABLED, pdev->name, davinci_ks);
0, pdev->name, davinci_ks);
if (error < 0) {
dev_err(dev, "unable to register davinci key scan interrupt\n");
goto fail5;

View file

@ -323,7 +323,7 @@ static int __devinit ep93xx_keypad_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, keypad);
err = request_irq(keypad->irq, ep93xx_keypad_irq_handler,
IRQF_DISABLED, pdev->name, keypad);
0, pdev->name, keypad);
if (err)
goto failed_free_dev;

View file

@ -461,8 +461,7 @@ static int gpio_keys_get_devtree_pdata(struct device *dev,
struct device_node *node, *pp;
int i;
struct gpio_keys_button *buttons;
const u32 *reg;
int len;
u32 reg;
node = dev->of_node;
if (node == NULL)
@ -470,7 +469,7 @@ static int gpio_keys_get_devtree_pdata(struct device *dev,
memset(pdata, 0, sizeof *pdata);
pdata->rep = !!of_get_property(node, "autorepeat", &len);
pdata->rep = !!of_get_property(node, "autorepeat", NULL);
/* First count the subnodes */
pdata->nbuttons = 0;
@ -498,22 +497,25 @@ static int gpio_keys_get_devtree_pdata(struct device *dev,
buttons[i].gpio = of_get_gpio_flags(pp, 0, &flags);
buttons[i].active_low = flags & OF_GPIO_ACTIVE_LOW;
reg = of_get_property(pp, "linux,code", &len);
if (!reg) {
if (of_property_read_u32(pp, "linux,code", &reg)) {
dev_err(dev, "Button without keycode: 0x%x\n", buttons[i].gpio);
goto out_fail;
}
buttons[i].code = be32_to_cpup(reg);
buttons[i].code = reg;
buttons[i].desc = of_get_property(pp, "label", &len);
buttons[i].desc = of_get_property(pp, "label", NULL);
reg = of_get_property(pp, "linux,input-type", &len);
buttons[i].type = reg ? be32_to_cpup(reg) : EV_KEY;
if (of_property_read_u32(pp, "linux,input-type", &reg) == 0)
buttons[i].type = reg;
else
buttons[i].type = EV_KEY;
buttons[i].wakeup = !!of_get_property(pp, "gpio-key,wakeup", NULL);
reg = of_get_property(pp, "debounce-interval", &len);
buttons[i].debounce_interval = reg ? be32_to_cpup(reg) : 5;
if (of_property_read_u32(pp, "debounce-interval", &reg) == 0)
buttons[i].debounce_interval = reg;
else
buttons[i].debounce_interval = 5;
i++;
}

View file

@ -510,7 +510,7 @@ static int __devinit imx_keypad_probe(struct platform_device *pdev)
/* Ensure that the keypad will stay dormant until opened */
imx_keypad_inhibit(keypad);
error = request_irq(irq, imx_keypad_irq_handler, IRQF_DISABLED,
error = request_irq(irq, imx_keypad_irq_handler, 0,
pdev->name, keypad);
if (error) {
dev_err(&pdev->dev, "failed to request IRQ\n");
@ -567,10 +567,54 @@ static int __devexit imx_keypad_remove(struct platform_device *pdev)
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int imx_kbd_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct imx_keypad *kbd = platform_get_drvdata(pdev);
struct input_dev *input_dev = kbd->input_dev;
/* imx kbd can wake up system even clock is disabled */
mutex_lock(&input_dev->mutex);
if (input_dev->users)
clk_disable(kbd->clk);
mutex_unlock(&input_dev->mutex);
if (device_may_wakeup(&pdev->dev))
enable_irq_wake(kbd->irq);
return 0;
}
static int imx_kbd_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct imx_keypad *kbd = platform_get_drvdata(pdev);
struct input_dev *input_dev = kbd->input_dev;
if (device_may_wakeup(&pdev->dev))
disable_irq_wake(kbd->irq);
mutex_lock(&input_dev->mutex);
if (input_dev->users)
clk_enable(kbd->clk);
mutex_unlock(&input_dev->mutex);
return 0;
}
#endif
static SIMPLE_DEV_PM_OPS(imx_kbd_pm_ops, imx_kbd_suspend, imx_kbd_resume);
static struct platform_driver imx_keypad_driver = {
.driver = {
.name = "imx-keypad",
.owner = THIS_MODULE,
.pm = &imx_kbd_pm_ops,
},
.probe = imx_keypad_probe,
.remove = __devexit_p(imx_keypad_remove),

View file

@ -129,7 +129,7 @@ static int __devinit jornada720_kbd_probe(struct platform_device *pdev)
err = request_irq(IRQ_GPIO0,
jornada720_kbd_interrupt,
IRQF_DISABLED | IRQF_TRIGGER_FALLING,
IRQF_TRIGGER_FALLING,
"jornadakbd", pdev);
if (err) {
printk(KERN_INFO "jornadakbd720_kbd: Unable to grab IRQ\n");

View file

@ -788,7 +788,7 @@ static int __devexit lm8323_remove(struct i2c_client *client)
return 0;
}
#ifdef CONFIG_PM
#ifdef CONFIG_PM_SLEEP
/*
* We don't need to explicitly suspend the chip, as it already switches off
* when there's no activity.

View file

@ -343,7 +343,6 @@ static int __devinit init_matrix_gpio(struct platform_device *pdev,
for (i = 0; i < pdata->num_row_gpios; i++) {
err = request_irq(gpio_to_irq(pdata->row_gpios[i]),
matrix_keypad_interrupt,
IRQF_DISABLED |
IRQF_TRIGGER_RISING |
IRQF_TRIGGER_FALLING,
"matrix-keypad", keypad);

View file

@ -535,7 +535,7 @@ static int __devinit pxa27x_keypad_probe(struct platform_device *pdev)
input_dev->evbit[0] |= BIT_MASK(EV_REL);
}
error = request_irq(irq, pxa27x_keypad_irq_handler, IRQF_DISABLED,
error = request_irq(irq, pxa27x_keypad_irq_handler, 0,
pdev->name, keypad);
if (error) {
dev_err(&pdev->dev, "failed to request IRQ\n");

View file

@ -148,7 +148,7 @@ static int __devinit pxa930_rotary_probe(struct platform_device *pdev)
r->input_dev = input_dev;
input_set_drvdata(input_dev, r);
err = request_irq(irq, rotary_irq, IRQF_DISABLED,
err = request_irq(irq, rotary_irq, 0,
"enhanced rotary", r);
if (err) {
dev_err(&pdev->dev, "failed to request IRQ\n");

View file

@ -90,7 +90,7 @@ struct tc_keypad {
bool keypad_stopped;
};
static int __devinit tc3589x_keypad_init_key_hardware(struct tc_keypad *keypad)
static int tc3589x_keypad_init_key_hardware(struct tc_keypad *keypad)
{
int ret;
struct tc3589x *tc3589x = keypad->tc3589x;

View file

@ -55,6 +55,7 @@
#define KBC_ROW_CFG0_0 0x8
#define KBC_COL_CFG0_0 0x18
#define KBC_TO_CNT_0 0x24
#define KBC_INIT_DLY_0 0x28
#define KBC_RPT_DLY_0 0x2c
#define KBC_KP_ENT0_0 0x30
@ -70,6 +71,7 @@ struct tegra_kbc {
spinlock_t lock;
unsigned int repoll_dly;
unsigned long cp_dly_jiffies;
unsigned int cp_to_wkup_dly;
bool use_fn_map;
bool use_ghost_filter;
const struct tegra_kbc_platform_data *pdata;
@ -258,12 +260,10 @@ static void tegra_kbc_report_keys(struct tegra_kbc *kbc)
u32 val = 0;
unsigned int i;
unsigned int num_down = 0;
unsigned long flags;
bool fn_keypress = false;
bool key_in_same_row = false;
bool key_in_same_col = false;
spin_lock_irqsave(&kbc->lock, flags);
for (i = 0; i < KBC_MAX_KPENT; i++) {
if ((i % 4) == 0)
val = readl(kbc->mmio + KBC_KP_ENT0_0 + i);
@ -292,7 +292,7 @@ static void tegra_kbc_report_keys(struct tegra_kbc *kbc)
* any 2 of the 3 keys share a row, and any 2 of them share a column.
* If so ignore the key presses for this iteration.
*/
if ((kbc->use_ghost_filter) && (num_down >= 3)) {
if (kbc->use_ghost_filter && num_down >= 3) {
for (i = 0; i < num_down; i++) {
unsigned int j;
u8 curr_col = scancodes[i] & 0x07;
@ -325,8 +325,6 @@ static void tegra_kbc_report_keys(struct tegra_kbc *kbc)
}
}
spin_unlock_irqrestore(&kbc->lock, flags);
/* Ignore the key presses for this iteration? */
if (key_in_same_col && key_in_same_row)
return;
@ -341,6 +339,18 @@ static void tegra_kbc_report_keys(struct tegra_kbc *kbc)
kbc->num_pressed_keys = num_down;
}
static void tegra_kbc_set_fifo_interrupt(struct tegra_kbc *kbc, bool enable)
{
u32 val;
val = readl(kbc->mmio + KBC_CONTROL_0);
if (enable)
val |= KBC_CONTROL_FIFO_CNT_INT_EN;
else
val &= ~KBC_CONTROL_FIFO_CNT_INT_EN;
writel(val, kbc->mmio + KBC_CONTROL_0);
}
static void tegra_kbc_keypress_timer(unsigned long data)
{
struct tegra_kbc *kbc = (struct tegra_kbc *)data;
@ -348,6 +358,8 @@ static void tegra_kbc_keypress_timer(unsigned long data)
u32 val;
unsigned int i;
spin_lock_irqsave(&kbc->lock, flags);
val = (readl(kbc->mmio + KBC_INT_0) >> 4) & 0xf;
if (val) {
unsigned long dly;
@ -369,26 +381,19 @@ static void tegra_kbc_keypress_timer(unsigned long data)
kbc->num_pressed_keys = 0;
/* All keys are released so enable the keypress interrupt */
spin_lock_irqsave(&kbc->lock, flags);
val = readl(kbc->mmio + KBC_CONTROL_0);
val |= KBC_CONTROL_FIFO_CNT_INT_EN;
writel(val, kbc->mmio + KBC_CONTROL_0);
spin_unlock_irqrestore(&kbc->lock, flags);
tegra_kbc_set_fifo_interrupt(kbc, true);
}
spin_unlock_irqrestore(&kbc->lock, flags);
}
static irqreturn_t tegra_kbc_isr(int irq, void *args)
{
struct tegra_kbc *kbc = args;
u32 val, ctl;
unsigned long flags;
u32 val;
/*
* Until all keys are released, defer further processing to
* the polling loop in tegra_kbc_keypress_timer
*/
ctl = readl(kbc->mmio + KBC_CONTROL_0);
ctl &= ~KBC_CONTROL_FIFO_CNT_INT_EN;
writel(ctl, kbc->mmio + KBC_CONTROL_0);
spin_lock_irqsave(&kbc->lock, flags);
/*
* Quickly bail out & reenable interrupts if the fifo threshold
@ -399,15 +404,15 @@ static irqreturn_t tegra_kbc_isr(int irq, void *args)
if (val & KBC_INT_FIFO_CNT_INT_STATUS) {
/*
* Schedule timer to run when hardware is in continuous
* polling mode.
* Until all keys are released, defer further processing to
* the polling loop in tegra_kbc_keypress_timer.
*/
tegra_kbc_set_fifo_interrupt(kbc, false);
mod_timer(&kbc->timer, jiffies + kbc->cp_dly_jiffies);
} else {
ctl |= KBC_CONTROL_FIFO_CNT_INT_EN;
writel(ctl, kbc->mmio + KBC_CONTROL_0);
}
spin_unlock_irqrestore(&kbc->lock, flags);
return IRQ_HANDLED;
}
@ -455,7 +460,6 @@ static void tegra_kbc_config_pins(struct tegra_kbc *kbc)
static int tegra_kbc_start(struct tegra_kbc *kbc)
{
const struct tegra_kbc_platform_data *pdata = kbc->pdata;
unsigned long flags;
unsigned int debounce_cnt;
u32 val = 0;
@ -493,7 +497,6 @@ static int tegra_kbc_start(struct tegra_kbc *kbc)
* Atomically clear out any remaining entries in the key FIFO
* and enable keyboard interrupts.
*/
spin_lock_irqsave(&kbc->lock, flags);
while (1) {
val = readl(kbc->mmio + KBC_INT_0);
val >>= 4;
@ -504,7 +507,6 @@ static int tegra_kbc_start(struct tegra_kbc *kbc)
val = readl(kbc->mmio + KBC_KP_ENT1_0);
}
writel(0x7, kbc->mmio + KBC_INT_0);
spin_unlock_irqrestore(&kbc->lock, flags);
enable_irq(kbc->irq);
@ -734,18 +736,30 @@ static int tegra_kbc_suspend(struct device *dev)
struct platform_device *pdev = to_platform_device(dev);
struct tegra_kbc *kbc = platform_get_drvdata(pdev);
mutex_lock(&kbc->idev->mutex);
if (device_may_wakeup(&pdev->dev)) {
tegra_kbc_setup_wakekeys(kbc, true);
enable_irq_wake(kbc->irq);
disable_irq(kbc->irq);
del_timer_sync(&kbc->timer);
tegra_kbc_set_fifo_interrupt(kbc, false);
/* Forcefully clear the interrupt status */
writel(0x7, kbc->mmio + KBC_INT_0);
/*
* Store the previous resident time of continuous polling mode.
* Force the keyboard into interrupt mode.
*/
kbc->cp_to_wkup_dly = readl(kbc->mmio + KBC_TO_CNT_0);
writel(0, kbc->mmio + KBC_TO_CNT_0);
tegra_kbc_setup_wakekeys(kbc, true);
msleep(30);
enable_irq_wake(kbc->irq);
} else {
mutex_lock(&kbc->idev->mutex);
if (kbc->idev->users)
tegra_kbc_stop(kbc);
mutex_unlock(&kbc->idev->mutex);
}
mutex_unlock(&kbc->idev->mutex);
return 0;
}
@ -756,15 +770,22 @@ static int tegra_kbc_resume(struct device *dev)
struct tegra_kbc *kbc = platform_get_drvdata(pdev);
int err = 0;
mutex_lock(&kbc->idev->mutex);
if (device_may_wakeup(&pdev->dev)) {
disable_irq_wake(kbc->irq);
tegra_kbc_setup_wakekeys(kbc, false);
/* Restore the resident time of continuous polling mode. */
writel(kbc->cp_to_wkup_dly, kbc->mmio + KBC_TO_CNT_0);
tegra_kbc_set_fifo_interrupt(kbc, true);
enable_irq(kbc->irq);
} else {
mutex_lock(&kbc->idev->mutex);
if (kbc->idev->users)
err = tegra_kbc_start(kbc);
mutex_unlock(&kbc->idev->mutex);
}
mutex_unlock(&kbc->idev->mutex);
return err;
}

View file

@ -203,7 +203,7 @@ static int __devinit w90p910_keypad_probe(struct platform_device *pdev)
input_dev->keycode, input_dev->keybit);
error = request_irq(keypad->irq, w90p910_keypad_irq_handler,
IRQF_DISABLED, pdev->name, keypad);
0, pdev->name, keypad);
if (error) {
dev_err(&pdev->dev, "failed to request IRQ\n");
goto failed_put_clk;

View file

@ -62,6 +62,17 @@ config INPUT_AD714X_SPI
To compile this driver as a module, choose M here: the
module will be called ad714x-spi.
config INPUT_BMA150
tristate "BMA150/SMB380 acceleration sensor support"
depends on I2C
select INPUT_POLLDEV
help
Say Y here if you have Bosch Sensortec's BMA150 or SMB380
acceleration sensor hooked to an I2C bus.
To compile this driver as a module, choose M here: the
module will be called bma150.
config INPUT_PCSPKR
tristate "PC Speaker support"
depends on PCSPKR_PLATFORM
@ -74,6 +85,29 @@ config INPUT_PCSPKR
To compile this driver as a module, choose M here: the
module will be called pcspkr.
config INPUT_PM8XXX_VIBRATOR
tristate "Qualcomm PM8XXX vibrator support"
depends on MFD_PM8XXX
select INPUT_FF_MEMLESS
help
This option enables device driver support for the vibrator
on Qualcomm PM8xxx chip. This driver supports ff-memless interface
from input framework.
To compile this driver as module, choose M here: the
module will be called pm8xxx-vibrator.
config INPUT_PMIC8XXX_PWRKEY
tristate "PMIC8XXX power key support"
depends on MFD_PM8XXX
help
Say Y here if you want support for the PMIC8XXX power key.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called pmic8xxx-pwrkey.
config INPUT_SPARCSPKR
tristate "SPARC Speaker support"
depends on PCI && SPARC64
@ -379,17 +413,6 @@ config INPUT_PWM_BEEPER
To compile this driver as a module, choose M here: the module will be
called pwm-beeper.
config INPUT_PMIC8XXX_PWRKEY
tristate "PMIC8XXX power key support"
depends on MFD_PM8XXX
help
Say Y here if you want support for the PMIC8XXX power key.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called pmic8xxx-pwrkey.
config INPUT_GPIO_ROTARY_ENCODER
tristate "Rotary encoders connected to GPIO pins"
depends on GPIOLIB && GENERIC_GPIO

View file

@ -17,6 +17,7 @@ obj-$(CONFIG_INPUT_ATI_REMOTE) += ati_remote.o
obj-$(CONFIG_INPUT_ATI_REMOTE2) += ati_remote2.o
obj-$(CONFIG_INPUT_ATLAS_BTNS) += atlas_btns.o
obj-$(CONFIG_INPUT_BFIN_ROTARY) += bfin_rotary.o
obj-$(CONFIG_INPUT_BMA150) += bma150.o
obj-$(CONFIG_INPUT_CM109) += cm109.o
obj-$(CONFIG_INPUT_CMA3000) += cma3000_d0x.o
obj-$(CONFIG_INPUT_CMA3000_I2C) += cma3000_d0x_i2c.o
@ -34,9 +35,10 @@ obj-$(CONFIG_INPUT_PCAP) += pcap_keys.o
obj-$(CONFIG_INPUT_PCF50633_PMU) += pcf50633-input.o
obj-$(CONFIG_INPUT_PCF8574) += pcf8574_keypad.o
obj-$(CONFIG_INPUT_PCSPKR) += pcspkr.o
obj-$(CONFIG_INPUT_PM8XXX_VIBRATOR) += pm8xxx-vibrator.o
obj-$(CONFIG_INPUT_PMIC8XXX_PWRKEY) += pmic8xxx-pwrkey.o
obj-$(CONFIG_INPUT_POWERMATE) += powermate.o
obj-$(CONFIG_INPUT_PWM_BEEPER) += pwm-beeper.o
obj-$(CONFIG_INPUT_PMIC8XXX_PWRKEY) += pmic8xxx-pwrkey.o
obj-$(CONFIG_INPUT_RB532_BUTTON) += rb532_button.o
obj-$(CONFIG_INPUT_GPIO_ROTARY_ENCODER) += rotary_encoder.o
obj-$(CONFIG_INPUT_SGI_BTNS) += sgi_btns.o

View file

@ -116,13 +116,13 @@ static struct i2c_driver ad714x_i2c_driver = {
.id_table = ad714x_id,
};
static __init int ad714x_i2c_init(void)
static int __init ad714x_i2c_init(void)
{
return i2c_add_driver(&ad714x_i2c_driver);
}
module_init(ad714x_i2c_init);
static __exit void ad714x_i2c_exit(void)
static void __exit ad714x_i2c_exit(void)
{
i2c_del_driver(&ad714x_i2c_driver);
}

691
drivers/input/misc/bma150.c Normal file
View file

@ -0,0 +1,691 @@
/*
* Copyright (c) 2011 Bosch Sensortec GmbH
* Copyright (c) 2011 Unixphere
*
* This driver adds support for Bosch Sensortec's digital acceleration
* sensors BMA150 and SMB380.
* The SMB380 is fully compatible with BMA150 and only differs in packaging.
*
* The datasheet for the BMA150 chip can be found here:
* http://www.bosch-sensortec.com/content/language1/downloads/BST-BMA150-DS000-07.pdf
*
* 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/module.h>
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/input-polldev.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/pm.h>
#include <linux/pm_runtime.h>
#include <linux/bma150.h>
#define ABSMAX_ACC_VAL 0x01FF
#define ABSMIN_ACC_VAL -(ABSMAX_ACC_VAL)
/* Each axis is represented by a 2-byte data word */
#define BMA150_XYZ_DATA_SIZE 6
/* Input poll interval in milliseconds */
#define BMA150_POLL_INTERVAL 10
#define BMA150_POLL_MAX 200
#define BMA150_POLL_MIN 0
#define BMA150_BW_25HZ 0
#define BMA150_BW_50HZ 1
#define BMA150_BW_100HZ 2
#define BMA150_BW_190HZ 3
#define BMA150_BW_375HZ 4
#define BMA150_BW_750HZ 5
#define BMA150_BW_1500HZ 6
#define BMA150_RANGE_2G 0
#define BMA150_RANGE_4G 1
#define BMA150_RANGE_8G 2
#define BMA150_MODE_NORMAL 0
#define BMA150_MODE_SLEEP 2
#define BMA150_MODE_WAKE_UP 3
/* Data register addresses */
#define BMA150_DATA_0_REG 0x00
#define BMA150_DATA_1_REG 0x01
#define BMA150_DATA_2_REG 0x02
/* Control register addresses */
#define BMA150_CTRL_0_REG 0x0A
#define BMA150_CTRL_1_REG 0x0B
#define BMA150_CTRL_2_REG 0x14
#define BMA150_CTRL_3_REG 0x15
/* Configuration/Setting register addresses */
#define BMA150_CFG_0_REG 0x0C
#define BMA150_CFG_1_REG 0x0D
#define BMA150_CFG_2_REG 0x0E
#define BMA150_CFG_3_REG 0x0F
#define BMA150_CFG_4_REG 0x10
#define BMA150_CFG_5_REG 0x11
#define BMA150_CHIP_ID 2
#define BMA150_CHIP_ID_REG BMA150_DATA_0_REG
#define BMA150_ACC_X_LSB_REG BMA150_DATA_2_REG
#define BMA150_SLEEP_POS 0
#define BMA150_SLEEP_MSK 0x01
#define BMA150_SLEEP_REG BMA150_CTRL_0_REG
#define BMA150_BANDWIDTH_POS 0
#define BMA150_BANDWIDTH_MSK 0x07
#define BMA150_BANDWIDTH_REG BMA150_CTRL_2_REG
#define BMA150_RANGE_POS 3
#define BMA150_RANGE_MSK 0x18
#define BMA150_RANGE_REG BMA150_CTRL_2_REG
#define BMA150_WAKE_UP_POS 0
#define BMA150_WAKE_UP_MSK 0x01
#define BMA150_WAKE_UP_REG BMA150_CTRL_3_REG
#define BMA150_SW_RES_POS 1
#define BMA150_SW_RES_MSK 0x02
#define BMA150_SW_RES_REG BMA150_CTRL_0_REG
/* Any-motion interrupt register fields */
#define BMA150_ANY_MOTION_EN_POS 6
#define BMA150_ANY_MOTION_EN_MSK 0x40
#define BMA150_ANY_MOTION_EN_REG BMA150_CTRL_1_REG
#define BMA150_ANY_MOTION_DUR_POS 6
#define BMA150_ANY_MOTION_DUR_MSK 0xC0
#define BMA150_ANY_MOTION_DUR_REG BMA150_CFG_5_REG
#define BMA150_ANY_MOTION_THRES_REG BMA150_CFG_4_REG
/* Advanced interrupt register fields */
#define BMA150_ADV_INT_EN_POS 6
#define BMA150_ADV_INT_EN_MSK 0x40
#define BMA150_ADV_INT_EN_REG BMA150_CTRL_3_REG
/* High-G interrupt register fields */
#define BMA150_HIGH_G_EN_POS 1
#define BMA150_HIGH_G_EN_MSK 0x02
#define BMA150_HIGH_G_EN_REG BMA150_CTRL_1_REG
#define BMA150_HIGH_G_HYST_POS 3
#define BMA150_HIGH_G_HYST_MSK 0x38
#define BMA150_HIGH_G_HYST_REG BMA150_CFG_5_REG
#define BMA150_HIGH_G_DUR_REG BMA150_CFG_3_REG
#define BMA150_HIGH_G_THRES_REG BMA150_CFG_2_REG
/* Low-G interrupt register fields */
#define BMA150_LOW_G_EN_POS 0
#define BMA150_LOW_G_EN_MSK 0x01
#define BMA150_LOW_G_EN_REG BMA150_CTRL_1_REG
#define BMA150_LOW_G_HYST_POS 0
#define BMA150_LOW_G_HYST_MSK 0x07
#define BMA150_LOW_G_HYST_REG BMA150_CFG_5_REG
#define BMA150_LOW_G_DUR_REG BMA150_CFG_1_REG
#define BMA150_LOW_G_THRES_REG BMA150_CFG_0_REG
struct bma150_data {
struct i2c_client *client;
struct input_polled_dev *input_polled;
struct input_dev *input;
u8 mode;
};
/*
* The settings for the given range, bandwidth and interrupt features
* are stated and verified by Bosch Sensortec where they are configured
* to provide a generic sensitivity performance.
*/
static struct bma150_cfg default_cfg __devinitdata = {
.any_motion_int = 1,
.hg_int = 1,
.lg_int = 1,
.any_motion_dur = 0,
.any_motion_thres = 0,
.hg_hyst = 0,
.hg_dur = 150,
.hg_thres = 160,
.lg_hyst = 0,
.lg_dur = 150,
.lg_thres = 20,
.range = BMA150_RANGE_2G,
.bandwidth = BMA150_BW_50HZ
};
static int bma150_write_byte(struct i2c_client *client, u8 reg, u8 val)
{
s32 ret;
/* As per specification, disable irq in between register writes */
if (client->irq)
disable_irq_nosync(client->irq);
ret = i2c_smbus_write_byte_data(client, reg, val);
if (client->irq)
enable_irq(client->irq);
return ret;
}
static int bma150_set_reg_bits(struct i2c_client *client,
int val, int shift, u8 mask, u8 reg)
{
int data;
data = i2c_smbus_read_byte_data(client, reg);
if (data < 0)
return data;
data = (data & ~mask) | ((val << shift) & mask);
return bma150_write_byte(client, reg, data);
}
static int bma150_set_mode(struct bma150_data *bma150, u8 mode)
{
int error;
error = bma150_set_reg_bits(bma150->client, mode, BMA150_WAKE_UP_POS,
BMA150_WAKE_UP_MSK, BMA150_WAKE_UP_REG);
if (error)
return error;
error = bma150_set_reg_bits(bma150->client, mode, BMA150_SLEEP_POS,
BMA150_SLEEP_MSK, BMA150_SLEEP_REG);
if (error)
return error;
if (mode == BMA150_MODE_NORMAL)
msleep(2);
bma150->mode = mode;
return 0;
}
static int __devinit bma150_soft_reset(struct bma150_data *bma150)
{
int error;
error = bma150_set_reg_bits(bma150->client, 1, BMA150_SW_RES_POS,
BMA150_SW_RES_MSK, BMA150_SW_RES_REG);
if (error)
return error;
msleep(2);
return 0;
}
static int __devinit bma150_set_range(struct bma150_data *bma150, u8 range)
{
return bma150_set_reg_bits(bma150->client, range, BMA150_RANGE_POS,
BMA150_RANGE_MSK, BMA150_RANGE_REG);
}
static int __devinit bma150_set_bandwidth(struct bma150_data *bma150, u8 bw)
{
return bma150_set_reg_bits(bma150->client, bw, BMA150_BANDWIDTH_POS,
BMA150_BANDWIDTH_MSK, BMA150_BANDWIDTH_REG);
}
static int __devinit bma150_set_low_g_interrupt(struct bma150_data *bma150,
u8 enable, u8 hyst, u8 dur, u8 thres)
{
int error;
error = bma150_set_reg_bits(bma150->client, hyst,
BMA150_LOW_G_HYST_POS, BMA150_LOW_G_HYST_MSK,
BMA150_LOW_G_HYST_REG);
if (error)
return error;
error = bma150_write_byte(bma150->client, BMA150_LOW_G_DUR_REG, dur);
if (error)
return error;
error = bma150_write_byte(bma150->client, BMA150_LOW_G_THRES_REG, thres);
if (error)
return error;
return bma150_set_reg_bits(bma150->client, !!enable,
BMA150_LOW_G_EN_POS, BMA150_LOW_G_EN_MSK,
BMA150_LOW_G_EN_REG);
}
static int __devinit bma150_set_high_g_interrupt(struct bma150_data *bma150,
u8 enable, u8 hyst, u8 dur, u8 thres)
{
int error;
error = bma150_set_reg_bits(bma150->client, hyst,
BMA150_HIGH_G_HYST_POS, BMA150_HIGH_G_HYST_MSK,
BMA150_HIGH_G_HYST_REG);
if (error)
return error;
error = bma150_write_byte(bma150->client,
BMA150_HIGH_G_DUR_REG, dur);
if (error)
return error;
error = bma150_write_byte(bma150->client,
BMA150_HIGH_G_THRES_REG, thres);
if (error)
return error;
return bma150_set_reg_bits(bma150->client, !!enable,
BMA150_HIGH_G_EN_POS, BMA150_HIGH_G_EN_MSK,
BMA150_HIGH_G_EN_REG);
}
static int __devinit bma150_set_any_motion_interrupt(struct bma150_data *bma150,
u8 enable, u8 dur, u8 thres)
{
int error;
error = bma150_set_reg_bits(bma150->client, dur,
BMA150_ANY_MOTION_DUR_POS,
BMA150_ANY_MOTION_DUR_MSK,
BMA150_ANY_MOTION_DUR_REG);
if (error)
return error;
error = bma150_write_byte(bma150->client,
BMA150_ANY_MOTION_THRES_REG, thres);
if (error)
return error;
error = bma150_set_reg_bits(bma150->client, !!enable,
BMA150_ADV_INT_EN_POS, BMA150_ADV_INT_EN_MSK,
BMA150_ADV_INT_EN_REG);
if (error)
return error;
return bma150_set_reg_bits(bma150->client, !!enable,
BMA150_ANY_MOTION_EN_POS,
BMA150_ANY_MOTION_EN_MSK,
BMA150_ANY_MOTION_EN_REG);
}
static void bma150_report_xyz(struct bma150_data *bma150)
{
u8 data[BMA150_XYZ_DATA_SIZE];
s16 x, y, z;
s32 ret;
ret = i2c_smbus_read_i2c_block_data(bma150->client,
BMA150_ACC_X_LSB_REG, BMA150_XYZ_DATA_SIZE, data);
if (ret != BMA150_XYZ_DATA_SIZE)
return;
x = ((0xc0 & data[0]) >> 6) | (data[1] << 2);
y = ((0xc0 & data[2]) >> 6) | (data[3] << 2);
z = ((0xc0 & data[4]) >> 6) | (data[5] << 2);
/* sign extension */
x = (s16) (x << 6) >> 6;
y = (s16) (y << 6) >> 6;
z = (s16) (z << 6) >> 6;
input_report_abs(bma150->input, ABS_X, x);
input_report_abs(bma150->input, ABS_Y, y);
input_report_abs(bma150->input, ABS_Z, z);
input_sync(bma150->input);
}
static irqreturn_t bma150_irq_thread(int irq, void *dev)
{
bma150_report_xyz(dev);
return IRQ_HANDLED;
}
static void bma150_poll(struct input_polled_dev *dev)
{
bma150_report_xyz(dev->private);
}
static int bma150_open(struct bma150_data *bma150)
{
int error;
error = pm_runtime_get_sync(&bma150->client->dev);
if (error && error != -ENOSYS)
return error;
/*
* See if runtime PM woke up the device. If runtime PM
* is disabled we need to do it ourselves.
*/
if (bma150->mode != BMA150_MODE_NORMAL) {
error = bma150_set_mode(bma150, BMA150_MODE_NORMAL);
if (error)
return error;
}
return 0;
}
static void bma150_close(struct bma150_data *bma150)
{
pm_runtime_put_sync(&bma150->client->dev);
if (bma150->mode != BMA150_MODE_SLEEP)
bma150_set_mode(bma150, BMA150_MODE_SLEEP);
}
static int bma150_irq_open(struct input_dev *input)
{
struct bma150_data *bma150 = input_get_drvdata(input);
return bma150_open(bma150);
}
static void bma150_irq_close(struct input_dev *input)
{
struct bma150_data *bma150 = input_get_drvdata(input);
bma150_close(bma150);
}
static void bma150_poll_open(struct input_polled_dev *ipoll_dev)
{
struct bma150_data *bma150 = ipoll_dev->private;
bma150_open(bma150);
}
static void bma150_poll_close(struct input_polled_dev *ipoll_dev)
{
struct bma150_data *bma150 = ipoll_dev->private;
bma150_close(bma150);
}
static int __devinit bma150_initialize(struct bma150_data *bma150,
const struct bma150_cfg *cfg)
{
int error;
error = bma150_soft_reset(bma150);
if (error)
return error;
error = bma150_set_bandwidth(bma150, cfg->bandwidth);
if (error)
return error;
error = bma150_set_range(bma150, cfg->range);
if (error)
return error;
if (bma150->client->irq) {
error = bma150_set_any_motion_interrupt(bma150,
cfg->any_motion_int,
cfg->any_motion_dur,
cfg->any_motion_thres);
if (error)
return error;
error = bma150_set_high_g_interrupt(bma150,
cfg->hg_int, cfg->hg_hyst,
cfg->hg_dur, cfg->hg_thres);
if (error)
return error;
error = bma150_set_low_g_interrupt(bma150,
cfg->lg_int, cfg->lg_hyst,
cfg->lg_dur, cfg->lg_thres);
if (error)
return error;
}
return bma150_set_mode(bma150, BMA150_MODE_SLEEP);
}
static void __devinit bma150_init_input_device(struct bma150_data *bma150,
struct input_dev *idev)
{
idev->name = BMA150_DRIVER;
idev->phys = BMA150_DRIVER "/input0";
idev->id.bustype = BUS_I2C;
idev->dev.parent = &bma150->client->dev;
idev->evbit[0] = BIT_MASK(EV_ABS);
input_set_abs_params(idev, ABS_X, ABSMIN_ACC_VAL, ABSMAX_ACC_VAL, 0, 0);
input_set_abs_params(idev, ABS_Y, ABSMIN_ACC_VAL, ABSMAX_ACC_VAL, 0, 0);
input_set_abs_params(idev, ABS_Z, ABSMIN_ACC_VAL, ABSMAX_ACC_VAL, 0, 0);
}
static int __devinit bma150_register_input_device(struct bma150_data *bma150)
{
struct input_dev *idev;
int error;
idev = input_allocate_device();
if (!idev)
return -ENOMEM;
bma150_init_input_device(bma150, idev);
idev->open = bma150_irq_open;
idev->close = bma150_irq_close;
input_set_drvdata(idev, bma150);
error = input_register_device(idev);
if (error) {
input_free_device(idev);
return error;
}
bma150->input = idev;
return 0;
}
static int __devinit bma150_register_polled_device(struct bma150_data *bma150)
{
struct input_polled_dev *ipoll_dev;
int error;
ipoll_dev = input_allocate_polled_device();
if (!ipoll_dev)
return -ENOMEM;
ipoll_dev->private = bma150;
ipoll_dev->open = bma150_poll_open;
ipoll_dev->close = bma150_poll_close;
ipoll_dev->poll = bma150_poll;
ipoll_dev->poll_interval = BMA150_POLL_INTERVAL;
ipoll_dev->poll_interval_min = BMA150_POLL_MIN;
ipoll_dev->poll_interval_max = BMA150_POLL_MAX;
bma150_init_input_device(bma150, ipoll_dev->input);
error = input_register_polled_device(ipoll_dev);
if (error) {
input_free_polled_device(ipoll_dev);
return error;
}
bma150->input_polled = ipoll_dev;
bma150->input = ipoll_dev->input;
return 0;
}
static int __devinit bma150_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
const struct bma150_platform_data *pdata = client->dev.platform_data;
const struct bma150_cfg *cfg;
struct bma150_data *bma150;
int chip_id;
int error;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
dev_err(&client->dev, "i2c_check_functionality error\n");
return -EIO;
}
chip_id = i2c_smbus_read_byte_data(client, BMA150_CHIP_ID_REG);
if (chip_id != BMA150_CHIP_ID) {
dev_err(&client->dev, "BMA150 chip id error: %d\n", chip_id);
return -EINVAL;
}
bma150 = kzalloc(sizeof(struct bma150_data), GFP_KERNEL);
if (!bma150)
return -ENOMEM;
bma150->client = client;
if (pdata) {
if (pdata->irq_gpio_cfg) {
error = pdata->irq_gpio_cfg();
if (error) {
dev_err(&client->dev,
"IRQ GPIO conf. error %d, error %d\n",
client->irq, error);
goto err_free_mem;
}
}
cfg = &pdata->cfg;
} else {
cfg = &default_cfg;
}
error = bma150_initialize(bma150, cfg);
if (error)
goto err_free_mem;
if (client->irq > 0) {
error = bma150_register_input_device(bma150);
if (error)
goto err_free_mem;
error = request_threaded_irq(client->irq,
NULL, bma150_irq_thread,
IRQF_TRIGGER_RISING | IRQF_ONESHOT,
BMA150_DRIVER, bma150);
if (error) {
dev_err(&client->dev,
"irq request failed %d, error %d\n",
client->irq, error);
input_unregister_device(bma150->input);
goto err_free_mem;
}
} else {
error = bma150_register_polled_device(bma150);
if (error)
goto err_free_mem;
}
i2c_set_clientdata(client, bma150);
pm_runtime_enable(&client->dev);
return 0;
err_free_mem:
kfree(bma150);
return error;
}
static int __devexit bma150_remove(struct i2c_client *client)
{
struct bma150_data *bma150 = i2c_get_clientdata(client);
pm_runtime_disable(&client->dev);
if (client->irq > 0) {
free_irq(client->irq, bma150);
input_unregister_device(bma150->input);
} else {
input_unregister_polled_device(bma150->input_polled);
input_free_polled_device(bma150->input_polled);
}
kfree(bma150);
return 0;
}
#ifdef CONFIG_PM
static int bma150_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct bma150_data *bma150 = i2c_get_clientdata(client);
return bma150_set_mode(bma150, BMA150_MODE_SLEEP);
}
static int bma150_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct bma150_data *bma150 = i2c_get_clientdata(client);
return bma150_set_mode(bma150, BMA150_MODE_NORMAL);
}
#endif
static UNIVERSAL_DEV_PM_OPS(bma150_pm, bma150_suspend, bma150_resume, NULL);
static const struct i2c_device_id bma150_id[] = {
{ "bma150", 0 },
{ "smb380", 0 },
{ "bma023", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, bma150_id);
static struct i2c_driver bma150_driver = {
.driver = {
.owner = THIS_MODULE,
.name = BMA150_DRIVER,
.pm = &bma150_pm,
},
.class = I2C_CLASS_HWMON,
.id_table = bma150_id,
.probe = bma150_probe,
.remove = __devexit_p(bma150_remove),
};
static int __init BMA150_init(void)
{
return i2c_add_driver(&bma150_driver);
}
static void __exit BMA150_exit(void)
{
i2c_del_driver(&bma150_driver);
}
MODULE_AUTHOR("Albert Zhang <xu.zhang@bosch-sensortec.com>");
MODULE_DESCRIPTION("BMA150 driver");
MODULE_LICENSE("GPL");
module_init(BMA150_init);
module_exit(BMA150_exit);

View file

@ -111,7 +111,7 @@ static int __devinit ixp4xx_spkr_probe(struct platform_device *dev)
input_dev->event = ixp4xx_spkr_event;
err = request_irq(IRQ_IXP4XX_TIMER2, &ixp4xx_spkr_interrupt,
IRQF_DISABLED | IRQF_NO_SUSPEND, "ixp4xx-beeper",
IRQF_NO_SUSPEND, "ixp4xx-beeper",
(void *) dev->id);
if (err)
goto err_free_device;

View file

@ -88,13 +88,13 @@ static int mma8450_write(struct mma8450 *m, unsigned off, u8 v)
return 0;
}
static int mma8450_read_xyz(struct mma8450 *m, int *x, int *y, int *z)
static int mma8450_read_block(struct mma8450 *m, unsigned off,
u8 *buf, size_t size)
{
struct i2c_client *c = m->client;
u8 buff[6];
int err;
err = i2c_smbus_read_i2c_block_data(c, MMA8450_OUT_X_LSB, 6, buff);
err = i2c_smbus_read_i2c_block_data(c, off, size, buf);
if (err < 0) {
dev_err(&c->dev,
"failed to read block data at 0x%02x, error %d\n",
@ -102,10 +102,6 @@ static int mma8450_read_xyz(struct mma8450 *m, int *x, int *y, int *z)
return err;
}
*x = ((buff[1] << 4) & 0xff0) | (buff[0] & 0xf);
*y = ((buff[3] << 4) & 0xff0) | (buff[2] & 0xf);
*z = ((buff[5] << 4) & 0xff0) | (buff[4] & 0xf);
return 0;
}
@ -114,7 +110,7 @@ static void mma8450_poll(struct input_polled_dev *dev)
struct mma8450 *m = dev->private;
int x, y, z;
int ret;
int err;
u8 buf[6];
ret = mma8450_read(m, MMA8450_STATUS);
if (ret < 0)
@ -123,10 +119,14 @@ static void mma8450_poll(struct input_polled_dev *dev)
if (!(ret & MMA8450_STATUS_ZXYDR))
return;
err = mma8450_read_xyz(m, &x, &y, &z);
if (err)
ret = mma8450_read_block(m, MMA8450_OUT_X_LSB, buf, sizeof(buf));
if (ret < 0)
return;
x = ((buf[1] << 4) & 0xff0) | (buf[0] & 0xf);
y = ((buf[3] << 4) & 0xff0) | (buf[2] & 0xf);
z = ((buf[5] << 4) & 0xff0) | (buf[4] & 0xf);
input_report_abs(dev->input, ABS_X, x);
input_report_abs(dev->input, ABS_Y, y);
input_report_abs(dev->input, ABS_Z, z);

View file

@ -0,0 +1,296 @@
/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* 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.
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/platform_device.h>
#include <linux/input.h>
#include <linux/slab.h>
#include <linux/mfd/pm8xxx/core.h>
#define VIB_DRV 0x4A
#define VIB_DRV_SEL_MASK 0xf8
#define VIB_DRV_SEL_SHIFT 0x03
#define VIB_DRV_EN_MANUAL_MASK 0xfc
#define VIB_MAX_LEVEL_mV (3100)
#define VIB_MIN_LEVEL_mV (1200)
#define VIB_MAX_LEVELS (VIB_MAX_LEVEL_mV - VIB_MIN_LEVEL_mV)
#define MAX_FF_SPEED 0xff
/**
* struct pm8xxx_vib - structure to hold vibrator data
* @vib_input_dev: input device supporting force feedback
* @work: work structure to set the vibration parameters
* @dev: device supporting force feedback
* @speed: speed of vibration set from userland
* @active: state of vibrator
* @level: level of vibration to set in the chip
* @reg_vib_drv: VIB_DRV register value
*/
struct pm8xxx_vib {
struct input_dev *vib_input_dev;
struct work_struct work;
struct device *dev;
int speed;
int level;
bool active;
u8 reg_vib_drv;
};
/**
* pm8xxx_vib_read_u8 - helper to read a byte from pmic chip
* @vib: pointer to vibrator structure
* @data: placeholder for data to be read
* @reg: register address
*/
static int pm8xxx_vib_read_u8(struct pm8xxx_vib *vib,
u8 *data, u16 reg)
{
int rc;
rc = pm8xxx_readb(vib->dev->parent, reg, data);
if (rc < 0)
dev_warn(vib->dev, "Error reading pm8xxx reg 0x%x(0x%x)\n",
reg, rc);
return rc;
}
/**
* pm8xxx_vib_write_u8 - helper to write a byte to pmic chip
* @vib: pointer to vibrator structure
* @data: data to write
* @reg: register address
*/
static int pm8xxx_vib_write_u8(struct pm8xxx_vib *vib,
u8 data, u16 reg)
{
int rc;
rc = pm8xxx_writeb(vib->dev->parent, reg, data);
if (rc < 0)
dev_warn(vib->dev, "Error writing pm8xxx reg 0x%x(0x%x)\n",
reg, rc);
return rc;
}
/**
* pm8xxx_vib_set - handler to start/stop vibration
* @vib: pointer to vibrator structure
* @on: state to set
*/
static int pm8xxx_vib_set(struct pm8xxx_vib *vib, bool on)
{
int rc;
u8 val = vib->reg_vib_drv;
if (on)
val |= ((vib->level << VIB_DRV_SEL_SHIFT) & VIB_DRV_SEL_MASK);
else
val &= ~VIB_DRV_SEL_MASK;
rc = pm8xxx_vib_write_u8(vib, val, VIB_DRV);
if (rc < 0)
return rc;
vib->reg_vib_drv = val;
return 0;
}
/**
* pm8xxx_work_handler - worker to set vibration level
* @work: pointer to work_struct
*/
static void pm8xxx_work_handler(struct work_struct *work)
{
struct pm8xxx_vib *vib = container_of(work, struct pm8xxx_vib, work);
int rc;
u8 val;
rc = pm8xxx_vib_read_u8(vib, &val, VIB_DRV);
if (rc < 0)
return;
/*
* pmic vibrator supports voltage ranges from 1.2 to 3.1V, so
* scale the level to fit into these ranges.
*/
if (vib->speed) {
vib->active = true;
vib->level = ((VIB_MAX_LEVELS * vib->speed) / MAX_FF_SPEED) +
VIB_MIN_LEVEL_mV;
vib->level /= 100;
} else {
vib->active = false;
vib->level = VIB_MIN_LEVEL_mV / 100;
}
pm8xxx_vib_set(vib, vib->active);
}
/**
* pm8xxx_vib_close - callback of input close callback
* @dev: input device pointer
*
* Turns off the vibrator.
*/
static void pm8xxx_vib_close(struct input_dev *dev)
{
struct pm8xxx_vib *vib = input_get_drvdata(dev);
cancel_work_sync(&vib->work);
if (vib->active)
pm8xxx_vib_set(vib, false);
}
/**
* pm8xxx_vib_play_effect - function to handle vib effects.
* @dev: input device pointer
* @data: data of effect
* @effect: effect to play
*
* Currently this driver supports only rumble effects.
*/
static int pm8xxx_vib_play_effect(struct input_dev *dev, void *data,
struct ff_effect *effect)
{
struct pm8xxx_vib *vib = input_get_drvdata(dev);
vib->speed = effect->u.rumble.strong_magnitude >> 8;
if (!vib->speed)
vib->speed = effect->u.rumble.weak_magnitude >> 9;
schedule_work(&vib->work);
return 0;
}
static int __devinit pm8xxx_vib_probe(struct platform_device *pdev)
{
struct pm8xxx_vib *vib;
struct input_dev *input_dev;
int error;
u8 val;
vib = kzalloc(sizeof(*vib), GFP_KERNEL);
input_dev = input_allocate_device();
if (!vib || !input_dev) {
dev_err(&pdev->dev, "couldn't allocate memory\n");
error = -ENOMEM;
goto err_free_mem;
}
INIT_WORK(&vib->work, pm8xxx_work_handler);
vib->dev = &pdev->dev;
vib->vib_input_dev = input_dev;
/* operate in manual mode */
error = pm8xxx_vib_read_u8(vib, &val, VIB_DRV);
if (error < 0)
goto err_free_mem;
val &= ~VIB_DRV_EN_MANUAL_MASK;
error = pm8xxx_vib_write_u8(vib, val, VIB_DRV);
if (error < 0)
goto err_free_mem;
vib->reg_vib_drv = val;
input_dev->name = "pm8xxx_vib_ffmemless";
input_dev->id.version = 1;
input_dev->dev.parent = &pdev->dev;
input_dev->close = pm8xxx_vib_close;
input_set_drvdata(input_dev, vib);
input_set_capability(vib->vib_input_dev, EV_FF, FF_RUMBLE);
error = input_ff_create_memless(input_dev, NULL,
pm8xxx_vib_play_effect);
if (error) {
dev_err(&pdev->dev,
"couldn't register vibrator as FF device\n");
goto err_free_mem;
}
error = input_register_device(input_dev);
if (error) {
dev_err(&pdev->dev, "couldn't register input device\n");
goto err_destroy_memless;
}
platform_set_drvdata(pdev, vib);
return 0;
err_destroy_memless:
input_ff_destroy(input_dev);
err_free_mem:
input_free_device(input_dev);
kfree(vib);
return error;
}
static int __devexit pm8xxx_vib_remove(struct platform_device *pdev)
{
struct pm8xxx_vib *vib = platform_get_drvdata(pdev);
input_unregister_device(vib->vib_input_dev);
kfree(vib);
platform_set_drvdata(pdev, NULL);
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int pm8xxx_vib_suspend(struct device *dev)
{
struct pm8xxx_vib *vib = dev_get_drvdata(dev);
/* Turn off the vibrator */
pm8xxx_vib_set(vib, false);
return 0;
}
#endif
static SIMPLE_DEV_PM_OPS(pm8xxx_vib_pm_ops, pm8xxx_vib_suspend, NULL);
static struct platform_driver pm8xxx_vib_driver = {
.probe = pm8xxx_vib_probe,
.remove = __devexit_p(pm8xxx_vib_remove),
.driver = {
.name = "pm8xxx-vib",
.owner = THIS_MODULE,
.pm = &pm8xxx_vib_pm_ops,
},
};
static int __init pm8xxx_vib_init(void)
{
return platform_driver_register(&pm8xxx_vib_driver);
}
module_init(pm8xxx_vib_init);
static void __exit pm8xxx_vib_exit(void)
{
platform_driver_unregister(&pm8xxx_vib_driver);
}
module_exit(pm8xxx_vib_exit);
MODULE_ALIAS("platform:pm8xxx_vib");
MODULE_DESCRIPTION("PMIC8xxx vibrator driver based on ff-memless framework");
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Amy Maloche <amaloche@codeaurora.org>");

View file

@ -228,7 +228,7 @@ static void twl6040_vibra_close(struct input_dev *input)
mutex_unlock(&info->mutex);
}
#if CONFIG_PM_SLEEP
#ifdef CONFIG_PM_SLEEP
static int twl6040_vibra_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);

View file

@ -23,13 +23,6 @@
#include "psmouse.h"
#include "alps.h"
#undef DEBUG
#ifdef DEBUG
#define dbg(format, arg...) printk(KERN_INFO "alps.c: " format "\n", ## arg)
#else
#define dbg(format, arg...) do {} while (0)
#endif
#define ALPS_OLDPROTO 0x01 /* old style input */
#define ALPS_DUALPOINT 0x02 /* touchpad has trackstick */
#define ALPS_PASS 0x04 /* device has a pass-through port */
@ -297,10 +290,10 @@ static psmouse_ret_t alps_handle_interleaved_ps2(struct psmouse *psmouse)
psmouse->packet[4] |
psmouse->packet[5]) & 0x80) ||
(!alps_is_valid_first_byte(priv->i, psmouse->packet[6]))) {
dbg("refusing packet %x %x %x %x "
"(suspected interleaved ps/2)\n",
psmouse->packet[3], psmouse->packet[4],
psmouse->packet[5], psmouse->packet[6]);
psmouse_dbg(psmouse,
"refusing packet %x %x %x %x (suspected interleaved ps/2)\n",
psmouse->packet[3], psmouse->packet[4],
psmouse->packet[5], psmouse->packet[6]);
return PSMOUSE_BAD_DATA;
}
@ -319,13 +312,13 @@ static psmouse_ret_t alps_handle_interleaved_ps2(struct psmouse *psmouse)
* There is also possibility that we got 6-byte ALPS
* packet followed by 3-byte packet from trackpoint. We
* can not distinguish between these 2 scenarios but
* becase the latter is unlikely to happen in course of
* because the latter is unlikely to happen in course of
* normal operation (user would need to press all
* buttons on the pad and start moving trackpoint
* without touching the pad surface) we assume former.
* Even if we are wrong the wost thing that would happen
* the cursor would jump but we should not get protocol
* desynchronization.
* de-synchronization.
*/
alps_report_bare_ps2_packet(psmouse, &psmouse->packet[3],
@ -361,10 +354,10 @@ static void alps_flush_packet(unsigned long data)
if ((psmouse->packet[3] |
psmouse->packet[4] |
psmouse->packet[5]) & 0x80) {
dbg("refusing packet %x %x %x "
"(suspected interleaved ps/2)\n",
psmouse->packet[3], psmouse->packet[4],
psmouse->packet[5]);
psmouse_dbg(psmouse,
"refusing packet %x %x %x (suspected interleaved ps/2)\n",
psmouse->packet[3], psmouse->packet[4],
psmouse->packet[5]);
} else {
alps_process_packet(psmouse);
}
@ -396,16 +389,18 @@ static psmouse_ret_t alps_process_byte(struct psmouse *psmouse)
}
if (!alps_is_valid_first_byte(model, psmouse->packet[0])) {
dbg("refusing packet[0] = %x (mask0 = %x, byte0 = %x)\n",
psmouse->packet[0], model->mask0, model->byte0);
psmouse_dbg(psmouse,
"refusing packet[0] = %x (mask0 = %x, byte0 = %x)\n",
psmouse->packet[0], model->mask0, model->byte0);
return PSMOUSE_BAD_DATA;
}
/* Bytes 2 - 6 should have 0 in the highest bit */
if (psmouse->pktcnt >= 2 && psmouse->pktcnt <= 6 &&
(psmouse->packet[psmouse->pktcnt - 1] & 0x80)) {
dbg("refusing packet[%i] = %x\n",
psmouse->pktcnt - 1, psmouse->packet[psmouse->pktcnt - 1]);
psmouse_dbg(psmouse, "refusing packet[%i] = %x\n",
psmouse->pktcnt - 1,
psmouse->packet[psmouse->pktcnt - 1]);
return PSMOUSE_BAD_DATA;
}
@ -439,7 +434,8 @@ static const struct alps_model_info *alps_get_model(struct psmouse *psmouse, int
if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO))
return NULL;
dbg("E6 report: %2.2x %2.2x %2.2x", param[0], param[1], param[2]);
psmouse_dbg(psmouse, "E6 report: %2.2x %2.2x %2.2x",
param[0], param[1], param[2]);
if (param[0] != 0 || param[1] != 0 || (param[2] != 10 && param[2] != 100))
return NULL;
@ -459,7 +455,8 @@ static const struct alps_model_info *alps_get_model(struct psmouse *psmouse, int
if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO))
return NULL;
dbg("E7 report: %2.2x %2.2x %2.2x", param[0], param[1], param[2]);
psmouse_dbg(psmouse, "E7 report: %2.2x %2.2x %2.2x",
param[0], param[1], param[2]);
if (version) {
for (i = 0; i < ARRAY_SIZE(rates) && param[2] != rates[i]; i++)
@ -527,7 +524,8 @@ static int alps_get_status(struct psmouse *psmouse, char *param)
ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO))
return -1;
dbg("Status: %2.2x %2.2x %2.2x", param[0], param[1], param[2]);
psmouse_dbg(psmouse, "Status: %2.2x %2.2x %2.2x",
param[0], param[1], param[2]);
return 0;
}
@ -605,12 +603,12 @@ static int alps_hw_init(struct psmouse *psmouse)
}
if (alps_tap_mode(psmouse, true)) {
printk(KERN_WARNING "alps.c: Failed to enable hardware tapping\n");
psmouse_warn(psmouse, "Failed to enable hardware tapping\n");
return -1;
}
if (alps_absolute_mode(psmouse)) {
printk(KERN_ERR "alps.c: Failed to enable absolute mode\n");
psmouse_err(psmouse, "Failed to enable absolute mode\n");
return -1;
}
@ -621,7 +619,7 @@ static int alps_hw_init(struct psmouse *psmouse)
/* ALPS needs stream mode, otherwise it won't report any data */
if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETSTREAM)) {
printk(KERN_ERR "alps.c: Failed to enable stream mode\n");
psmouse_err(psmouse, "Failed to enable stream mode\n");
return -1;
}

File diff suppressed because it is too large Load diff

View file

@ -16,14 +16,17 @@
/*
* Command values for Synaptics style queries
*/
#define ETP_FW_ID_QUERY 0x00
#define ETP_FW_VERSION_QUERY 0x01
#define ETP_CAPABILITIES_QUERY 0x02
#define ETP_SAMPLE_QUERY 0x03
/*
* Command values for register reading or writing
*/
#define ETP_REGISTER_READ 0x10
#define ETP_REGISTER_WRITE 0x11
#define ETP_REGISTER_READWRITE 0x00
/*
* Hardware version 2 custom PS/2 command value
@ -66,16 +69,13 @@
#define ETP_YMAX_V1 (384 - ETP_EDGE_FUZZ_V1)
/*
* It seems the resolution for hardware version 2 doubled.
* Hence the X and Y ranges are doubled too.
* The bezel around the pad also appears to be smaller
* The resolution for older v2 hardware doubled.
* (newer v2's firmware provides command so we can query)
*/
#define ETP_EDGE_FUZZ_V2 8
#define ETP_XMIN_V2 ( 0 + ETP_EDGE_FUZZ_V2)
#define ETP_XMAX_V2 (1152 - ETP_EDGE_FUZZ_V2)
#define ETP_YMIN_V2 ( 0 + ETP_EDGE_FUZZ_V2)
#define ETP_YMAX_V2 ( 768 - ETP_EDGE_FUZZ_V2)
#define ETP_XMIN_V2 0
#define ETP_XMAX_V2 1152
#define ETP_YMIN_V2 0
#define ETP_YMAX_V2 768
#define ETP_PMIN_V2 0
#define ETP_PMAX_V2 255
@ -83,17 +83,37 @@
#define ETP_WMAX_V2 15
/*
* For two finger touches the coordinate of each finger gets reported
* separately but with reduced resolution.
* v3 hardware has 2 kinds of packet types,
* v4 hardware has 3.
*/
#define ETP_2FT_FUZZ 4
#define PACKET_UNKNOWN 0x01
#define PACKET_DEBOUNCE 0x02
#define PACKET_V3_HEAD 0x03
#define PACKET_V3_TAIL 0x04
#define PACKET_V4_HEAD 0x05
#define PACKET_V4_MOTION 0x06
#define PACKET_V4_STATUS 0x07
#define ETP_2FT_XMIN ( 0 + ETP_2FT_FUZZ)
#define ETP_2FT_XMAX (288 - ETP_2FT_FUZZ)
#define ETP_2FT_YMIN ( 0 + ETP_2FT_FUZZ)
#define ETP_2FT_YMAX (192 - ETP_2FT_FUZZ)
/*
* track up to 5 fingers for v4 hardware
*/
#define ETP_MAX_FINGERS 5
/*
* weight value for v4 hardware
*/
#define ETP_WEIGHT_VALUE 5
/*
* The base position for one finger, v4 hardware
*/
struct finger_pos {
unsigned int x;
unsigned int y;
};
struct elantech_data {
unsigned char reg_07;
unsigned char reg_10;
unsigned char reg_11;
unsigned char reg_20;
@ -104,13 +124,16 @@ struct elantech_data {
unsigned char reg_25;
unsigned char reg_26;
unsigned char debug;
unsigned char capabilities;
unsigned char capabilities[3];
bool paritycheck;
bool jumpy_cursor;
bool reports_pressure;
unsigned char hw_version;
unsigned int fw_version;
unsigned int single_finger_reports;
unsigned int y_max;
unsigned int width;
struct finger_pos mt[ETP_MAX_FINGERS];
unsigned char parity[256];
};

View file

@ -136,10 +136,10 @@ static int hgpk_discard_decay_hack(struct psmouse *psmouse, int x, int y)
/* discard if too big, or half that but > 4 times the prev delta */
if (avx > recalib_delta ||
(avx > recalib_delta / 2 && ((avx / 4) > priv->xlast))) {
hgpk_err(psmouse, "detected %dpx jump in x\n", x);
psmouse_warn(psmouse, "detected %dpx jump in x\n", x);
priv->xbigj = avx;
} else if (approx_half(avx, priv->xbigj)) {
hgpk_err(psmouse, "detected secondary %dpx jump in x\n", x);
psmouse_warn(psmouse, "detected secondary %dpx jump in x\n", x);
priv->xbigj = avx;
priv->xsaw_secondary++;
} else {
@ -151,10 +151,10 @@ static int hgpk_discard_decay_hack(struct psmouse *psmouse, int x, int y)
if (avy > recalib_delta ||
(avy > recalib_delta / 2 && ((avy / 4) > priv->ylast))) {
hgpk_err(psmouse, "detected %dpx jump in y\n", y);
psmouse_warn(psmouse, "detected %dpx jump in y\n", y);
priv->ybigj = avy;
} else if (approx_half(avy, priv->ybigj)) {
hgpk_err(psmouse, "detected secondary %dpx jump in y\n", y);
psmouse_warn(psmouse, "detected secondary %dpx jump in y\n", y);
priv->ybigj = avy;
priv->ysaw_secondary++;
} else {
@ -168,7 +168,7 @@ static int hgpk_discard_decay_hack(struct psmouse *psmouse, int x, int y)
priv->ylast = avy;
if (do_recal && jumpy_delay) {
hgpk_err(psmouse, "scheduling recalibration\n");
psmouse_warn(psmouse, "scheduling recalibration\n");
psmouse_queue_work(psmouse, &priv->recalib_wq,
msecs_to_jiffies(jumpy_delay));
}
@ -260,8 +260,8 @@ static void hgpk_spewing_hack(struct psmouse *psmouse,
* movement, it is probably a case of the user moving the
* cursor very slowly across the screen. */
if (abs(priv->x_tally) < 3 && abs(priv->y_tally) < 3) {
hgpk_err(psmouse, "packet spew detected (%d,%d)\n",
priv->x_tally, priv->y_tally);
psmouse_warn(psmouse, "packet spew detected (%d,%d)\n",
priv->x_tally, priv->y_tally);
priv->spew_flag = RECALIBRATING;
psmouse_queue_work(psmouse, &priv->recalib_wq,
msecs_to_jiffies(spew_delay));
@ -333,12 +333,12 @@ static bool hgpk_is_byte_valid(struct psmouse *psmouse, unsigned char *packet)
}
if (!valid)
hgpk_dbg(psmouse,
"bad data, mode %d (%d) %02x %02x %02x %02x %02x %02x\n",
priv->mode, pktcnt,
psmouse->packet[0], psmouse->packet[1],
psmouse->packet[2], psmouse->packet[3],
psmouse->packet[4], psmouse->packet[5]);
psmouse_dbg(psmouse,
"bad data, mode %d (%d) %02x %02x %02x %02x %02x %02x\n",
priv->mode, pktcnt,
psmouse->packet[0], psmouse->packet[1],
psmouse->packet[2], psmouse->packet[3],
psmouse->packet[4], psmouse->packet[5]);
return valid;
}
@ -361,19 +361,20 @@ static void hgpk_process_advanced_packet(struct psmouse *psmouse)
input_report_abs(idev, ABS_PRESSURE, z);
if (tpdebug)
hgpk_dbg(psmouse, "pd=%d fd=%d z=%d",
pt_down, finger_down, z);
psmouse_dbg(psmouse, "pd=%d fd=%d z=%d",
pt_down, finger_down, z);
} else {
/*
* PenTablet mode does not report pressure, so we don't
* report it here
*/
if (tpdebug)
hgpk_dbg(psmouse, "pd=%d ", down);
psmouse_dbg(psmouse, "pd=%d ", down);
}
if (tpdebug)
hgpk_dbg(psmouse, "l=%d r=%d x=%d y=%d\n", left, right, x, y);
psmouse_dbg(psmouse, "l=%d r=%d x=%d y=%d\n",
left, right, x, y);
input_report_key(idev, BTN_TOUCH, down);
input_report_key(idev, BTN_LEFT, left);
@ -395,7 +396,7 @@ static void hgpk_process_advanced_packet(struct psmouse *psmouse)
if (x == priv->abs_x && y == priv->abs_y) {
if (++priv->dupe_count > SPEW_WATCH_COUNT) {
if (tpdebug)
hgpk_dbg(psmouse, "hard spew detected\n");
psmouse_dbg(psmouse, "hard spew detected\n");
priv->spew_flag = RECALIBRATING;
psmouse_queue_work(psmouse, &priv->recalib_wq,
msecs_to_jiffies(spew_delay));
@ -412,7 +413,7 @@ static void hgpk_process_advanced_packet(struct psmouse *psmouse)
int y_diff = priv->abs_y - y;
if (hgpk_discard_decay_hack(psmouse, x_diff, y_diff)) {
if (tpdebug)
hgpk_dbg(psmouse, "discarding\n");
psmouse_dbg(psmouse, "discarding\n");
goto done;
}
hgpk_spewing_hack(psmouse, left, right, x_diff, y_diff);
@ -437,20 +438,21 @@ static void hgpk_process_simple_packet(struct psmouse *psmouse)
int y = ((packet[0] << 3) & 0x100) - packet[2];
if (packet[0] & 0xc0)
hgpk_dbg(psmouse,
"overflow -- 0x%02x 0x%02x 0x%02x\n",
packet[0], packet[1], packet[2]);
psmouse_dbg(psmouse,
"overflow -- 0x%02x 0x%02x 0x%02x\n",
packet[0], packet[1], packet[2]);
if (hgpk_discard_decay_hack(psmouse, x, y)) {
if (tpdebug)
hgpk_dbg(psmouse, "discarding\n");
psmouse_dbg(psmouse, "discarding\n");
return;
}
hgpk_spewing_hack(psmouse, left, right, x, y);
if (tpdebug)
hgpk_dbg(psmouse, "l=%d r=%d x=%d y=%d\n", left, right, x, y);
psmouse_dbg(psmouse, "l=%d r=%d x=%d y=%d\n",
left, right, x, y);
input_report_key(dev, BTN_LEFT, left);
input_report_key(dev, BTN_RIGHT, right);
@ -482,9 +484,8 @@ static psmouse_ret_t hgpk_process_byte(struct psmouse *psmouse)
* ugh, got a packet inside our recalibration
* window, schedule another recalibration.
*/
hgpk_dbg(psmouse,
"packet inside calibration window, "
"queueing another recalibration\n");
psmouse_dbg(psmouse,
"packet inside calibration window, queueing another recalibration\n");
psmouse_queue_work(psmouse, &priv->recalib_wq,
msecs_to_jiffies(post_interrupt_delay));
}
@ -628,7 +629,7 @@ static int hgpk_reset_device(struct psmouse *psmouse, bool recalibrate)
err = hgpk_select_mode(psmouse);
if (err) {
hgpk_err(psmouse, "failed to select mode\n");
psmouse_err(psmouse, "failed to select mode\n");
return err;
}
@ -648,11 +649,11 @@ static int hgpk_force_recalibrate(struct psmouse *psmouse)
return 0;
if (!autorecal) {
hgpk_dbg(psmouse, "recalibrations disabled, ignoring\n");
psmouse_dbg(psmouse, "recalibration disabled, ignoring\n");
return 0;
}
hgpk_dbg(psmouse, "recalibrating touchpad..\n");
psmouse_dbg(psmouse, "recalibrating touchpad..\n");
/* we don't want to race with the irq handler, nor with resyncs */
psmouse_set_state(psmouse, PSMOUSE_INITIALIZING);
@ -675,7 +676,7 @@ static int hgpk_force_recalibrate(struct psmouse *psmouse)
psmouse_set_state(psmouse, PSMOUSE_ACTIVATED);
if (tpdebug)
hgpk_dbg(psmouse, "touchpad reactivated\n");
psmouse_dbg(psmouse, "touchpad reactivated\n");
/*
* If we get packets right away after recalibrating, it's likely
@ -727,16 +728,16 @@ static int hgpk_toggle_powersave(struct psmouse *psmouse, int enable)
err = hgpk_reset_device(psmouse, false);
if (err) {
hgpk_err(psmouse, "Failed to reset device!\n");
psmouse_err(psmouse, "Failed to reset device!\n");
return err;
}
/* should be all set, enable the touchpad */
ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_ENABLE);
psmouse_set_state(psmouse, PSMOUSE_ACTIVATED);
hgpk_dbg(psmouse, "Touchpad powered up.\n");
psmouse_dbg(psmouse, "Touchpad powered up.\n");
} else {
hgpk_dbg(psmouse, "Powering off touchpad.\n");
psmouse_dbg(psmouse, "Powering off touchpad.\n");
if (ps2_command(ps2dev, NULL, 0xec) ||
ps2_command(ps2dev, NULL, 0xec) ||
@ -923,7 +924,7 @@ static void hgpk_recalib_work(struct work_struct *work)
struct psmouse *psmouse = priv->psmouse;
if (hgpk_force_recalibrate(psmouse))
hgpk_err(psmouse, "recalibration failed!\n");
psmouse_err(psmouse, "recalibration failed!\n");
}
static int hgpk_register(struct psmouse *psmouse)
@ -947,14 +948,15 @@ static int hgpk_register(struct psmouse *psmouse)
err = device_create_file(&psmouse->ps2dev.serio->dev,
&psmouse_attr_powered.dattr);
if (err) {
hgpk_err(psmouse, "Failed creating 'powered' sysfs node\n");
psmouse_err(psmouse, "Failed creating 'powered' sysfs node\n");
return err;
}
err = device_create_file(&psmouse->ps2dev.serio->dev,
&psmouse_attr_hgpk_mode.dattr);
if (err) {
hgpk_err(psmouse, "Failed creating 'hgpk_mode' sysfs node\n");
psmouse_err(psmouse,
"Failed creating 'hgpk_mode' sysfs node\n");
goto err_remove_powered;
}
@ -963,8 +965,8 @@ static int hgpk_register(struct psmouse *psmouse)
err = device_create_file(&psmouse->ps2dev.serio->dev,
&psmouse_attr_recalibrate.dattr);
if (err) {
hgpk_err(psmouse,
"Failed creating 'recalibrate' sysfs node\n");
psmouse_err(psmouse,
"Failed creating 'recalibrate' sysfs node\n");
goto err_remove_mode;
}
}
@ -1027,13 +1029,13 @@ static enum hgpk_model_t hgpk_get_model(struct psmouse *psmouse)
return -EIO;
}
hgpk_dbg(psmouse, "ID: %02x %02x %02x\n", param[0], param[1], param[2]);
psmouse_dbg(psmouse, "ID: %02x %02x %02x\n", param[0], param[1], param[2]);
/* HGPK signature: 0x67, 0x00, 0x<model> */
if (param[0] != 0x67 || param[1] != 0x00)
return -ENODEV;
hgpk_info(psmouse, "OLPC touchpad revision 0x%x\n", param[2]);
psmouse_info(psmouse, "OLPC touchpad revision 0x%x\n", param[2]);
return param[2];
}

View file

@ -46,17 +46,6 @@ struct hgpk_data {
int xsaw_secondary, ysaw_secondary; /* jumpiness detection */
};
#define hgpk_dbg(psmouse, format, arg...) \
dev_dbg(&(psmouse)->ps2dev.serio->dev, format, ## arg)
#define hgpk_err(psmouse, format, arg...) \
dev_err(&(psmouse)->ps2dev.serio->dev, format, ## arg)
#define hgpk_info(psmouse, format, arg...) \
dev_info(&(psmouse)->ps2dev.serio->dev, format, ## arg)
#define hgpk_warn(psmouse, format, arg...) \
dev_warn(&(psmouse)->ps2dev.serio->dev, format, ## arg)
#define hgpk_notice(psmouse, format, arg...) \
dev_notice(&(psmouse)->ps2dev.serio->dev, format, ## arg)
#ifdef CONFIG_MOUSE_PS2_OLPC
void hgpk_module_init(void);
int hgpk_detect(struct psmouse *psmouse, bool set_properties);

View file

@ -169,8 +169,8 @@ static psmouse_ret_t lifebook_process_byte(struct psmouse *psmouse)
if (relative_packet) {
if (!dev2)
printk(KERN_WARNING "lifebook.c: got relative packet "
"but no relative device set up\n");
psmouse_warn(psmouse,
"got relative packet but no relative device set up\n");
} else {
if (lifebook_use_6byte_proto) {
input_report_abs(dev1, ABS_X,
@ -212,7 +212,7 @@ static int lifebook_absolute_mode(struct psmouse *psmouse)
/*
* Enable absolute output -- ps2_command fails always but if
* you leave this call out the touchsreen will never send
* you leave this call out the touchscreen will never send
* absolute coordinates
*/
param = lifebook_use_6byte_proto ? 0x08 : 0x07;

View file

@ -82,11 +82,11 @@ static psmouse_ret_t ps2pp_process_byte(struct psmouse *psmouse)
packet[0] = packet[2] | 0x08;
break;
#ifdef DEBUG
default:
printk(KERN_WARNING "psmouse.c: Received PS2++ packet #%x, but don't know how to handle.\n",
(packet[1] >> 4) | (packet[0] & 0x30));
#endif
psmouse_dbg(psmouse,
"Received PS2++ packet #%x, but don't know how to handle.\n",
(packet[1] >> 4) | (packet[0] & 0x30));
break;
}
} else {
/* Standard PS/2 motion data */
@ -382,7 +382,7 @@ int ps2pp_init(struct psmouse *psmouse, bool set_properties)
}
} else {
printk(KERN_WARNING "logips2pp: Detected unknown logitech mouse model %d\n", model);
psmouse_warn(psmouse, "Detected unknown Logitech mouse model %d\n", model);
}
if (set_properties) {
@ -400,9 +400,9 @@ int ps2pp_init(struct psmouse *psmouse, bool set_properties)
error = device_create_file(&psmouse->ps2dev.serio->dev,
&psmouse_attr_smartscroll.dattr);
if (error) {
printk(KERN_ERR
"logips2pp.c: failed to create smartscroll "
"sysfs attribute, error: %d\n", error);
psmouse_err(psmouse,
"failed to create smartscroll sysfs attribute, error: %d\n",
error);
return -1;
}
}

View file

@ -11,6 +11,9 @@
* the Free Software Foundation.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#define psmouse_fmt(fmt) fmt
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/slab.h>
@ -251,11 +254,14 @@ static int psmouse_handle_byte(struct psmouse *psmouse)
switch (rc) {
case PSMOUSE_BAD_DATA:
if (psmouse->state == PSMOUSE_ACTIVATED) {
printk(KERN_WARNING "psmouse.c: %s at %s lost sync at byte %d\n",
psmouse->name, psmouse->phys, psmouse->pktcnt);
psmouse_warn(psmouse,
"%s at %s lost sync at byte %d\n",
psmouse->name, psmouse->phys,
psmouse->pktcnt);
if (++psmouse->out_of_sync_cnt == psmouse->resetafter) {
__psmouse_set_state(psmouse, PSMOUSE_IGNORE);
printk(KERN_NOTICE "psmouse.c: issuing reconnect request\n");
psmouse_notice(psmouse,
"issuing reconnect request\n");
serio_reconnect(psmouse->ps2dev.serio);
return -1;
}
@ -267,8 +273,9 @@ static int psmouse_handle_byte(struct psmouse *psmouse)
psmouse->pktcnt = 0;
if (psmouse->out_of_sync_cnt) {
psmouse->out_of_sync_cnt = 0;
printk(KERN_NOTICE "psmouse.c: %s at %s - driver resynched.\n",
psmouse->name, psmouse->phys);
psmouse_notice(psmouse,
"%s at %s - driver resynced.\n",
psmouse->name, psmouse->phys);
}
break;
@ -295,9 +302,10 @@ static irqreturn_t psmouse_interrupt(struct serio *serio,
((flags & SERIO_PARITY) && !psmouse->ignore_parity))) {
if (psmouse->state == PSMOUSE_ACTIVATED)
printk(KERN_WARNING "psmouse.c: bad data from KBC -%s%s\n",
flags & SERIO_TIMEOUT ? " timeout" : "",
flags & SERIO_PARITY ? " bad parity" : "");
psmouse_warn(psmouse,
"bad data from KBC -%s%s\n",
flags & SERIO_TIMEOUT ? " timeout" : "",
flags & SERIO_PARITY ? " bad parity" : "");
ps2_cmd_aborted(&psmouse->ps2dev);
goto out;
}
@ -315,8 +323,8 @@ static irqreturn_t psmouse_interrupt(struct serio *serio,
if (psmouse->state == PSMOUSE_ACTIVATED &&
psmouse->pktcnt && time_after(jiffies, psmouse->last + HZ/2)) {
printk(KERN_INFO "psmouse.c: %s at %s lost synchronization, throwing %d bytes away.\n",
psmouse->name, psmouse->phys, psmouse->pktcnt);
psmouse_info(psmouse, "%s at %s lost synchronization, throwing %d bytes away.\n",
psmouse->name, psmouse->phys, psmouse->pktcnt);
psmouse->badbyte = psmouse->packet[0];
__psmouse_set_state(psmouse, PSMOUSE_RESYNCING);
psmouse_queue_work(psmouse, &psmouse->resync_work, 0);
@ -943,7 +951,8 @@ static int psmouse_probe(struct psmouse *psmouse)
*/
if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_RESET_DIS))
printk(KERN_WARNING "psmouse.c: Failed to reset mouse on %s\n", ps2dev->serio->phys);
psmouse_warn(psmouse, "Failed to reset mouse on %s\n",
ps2dev->serio->phys);
return 0;
}
@ -1005,8 +1014,8 @@ static void psmouse_initialize(struct psmouse *psmouse)
static void psmouse_activate(struct psmouse *psmouse)
{
if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_ENABLE))
printk(KERN_WARNING "psmouse.c: Failed to enable mouse on %s\n",
psmouse->ps2dev.serio->phys);
psmouse_warn(psmouse, "Failed to enable mouse on %s\n",
psmouse->ps2dev.serio->phys);
psmouse_set_state(psmouse, PSMOUSE_ACTIVATED);
}
@ -1020,14 +1029,14 @@ static void psmouse_activate(struct psmouse *psmouse)
static void psmouse_deactivate(struct psmouse *psmouse)
{
if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_DISABLE))
printk(KERN_WARNING "psmouse.c: Failed to deactivate mouse on %s\n",
psmouse->ps2dev.serio->phys);
psmouse_warn(psmouse, "Failed to deactivate mouse on %s\n",
psmouse->ps2dev.serio->phys);
psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
}
/*
* psmouse_poll() - default poll hanlder. Everyone except for ALPS uses it.
* psmouse_poll() - default poll handler. Everyone except for ALPS uses it.
*/
static int psmouse_poll(struct psmouse *psmouse)
@ -1115,14 +1124,15 @@ static void psmouse_resync(struct work_struct *work)
}
if (!enabled) {
printk(KERN_WARNING "psmouse.c: failed to re-enable mouse on %s\n",
psmouse->ps2dev.serio->phys);
psmouse_warn(psmouse, "failed to re-enable mouse on %s\n",
psmouse->ps2dev.serio->phys);
failed = true;
}
if (failed) {
psmouse_set_state(psmouse, PSMOUSE_IGNORE);
printk(KERN_INFO "psmouse.c: resync failed, issuing reconnect request\n");
psmouse_info(psmouse,
"resync failed, issuing reconnect request\n");
serio_reconnect(serio);
} else
psmouse_set_state(psmouse, PSMOUSE_ACTIVATED);
@ -1155,8 +1165,8 @@ static void psmouse_cleanup(struct serio *serio)
* Disable stream mode so cleanup routine can proceed undisturbed.
*/
if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_DISABLE))
printk(KERN_WARNING "psmouse.c: Failed to disable mouse on %s\n",
psmouse->ps2dev.serio->phys);
psmouse_warn(psmouse, "Failed to disable mouse on %s\n",
psmouse->ps2dev.serio->phys);
if (psmouse->cleanup)
psmouse->cleanup(psmouse);
@ -1400,7 +1410,8 @@ static int psmouse_reconnect(struct serio *serio)
int rc = -1;
if (!drv || !psmouse) {
printk(KERN_DEBUG "psmouse: reconnect request, but serio is disconnected, ignoring...\n");
psmouse_dbg(psmouse,
"reconnect request, but serio is disconnected, ignoring...\n");
return -1;
}
@ -1427,8 +1438,9 @@ static int psmouse_reconnect(struct serio *serio)
goto out;
}
/* ok, the device type (and capabilities) match the old one,
* we can continue using it, complete intialization
/*
* OK, the device type (and capabilities) match the old one,
* we can continue using it, complete initialization
*/
psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
@ -1586,9 +1598,8 @@ static ssize_t psmouse_attr_set_protocol(struct psmouse *psmouse, void *data, co
while (!list_empty(&serio->children)) {
if (++retry > 3) {
printk(KERN_WARNING
"psmouse: failed to destroy children ports, "
"protocol change aborted.\n");
psmouse_warn(psmouse,
"failed to destroy children ports, protocol change aborted.\n");
input_free_device(new_dev);
return -EIO;
}
@ -1715,7 +1726,7 @@ static int __init psmouse_init(void)
kpsmoused_wq = create_singlethread_workqueue("kpsmoused");
if (!kpsmoused_wq) {
printk(KERN_ERR "psmouse: failed to create kpsmoused workqueue\n");
pr_err("failed to create kpsmoused workqueue\n");
return -ENOMEM;
}

View file

@ -150,4 +150,29 @@ static struct psmouse_attribute psmouse_attr_##_name = { \
static ssize_t _set(struct psmouse *, void *, const char *, size_t); \
__PSMOUSE_DEFINE_ATTR_VAR(_name, _mode, _data, NULL, _set, true)
#ifndef psmouse_fmt
#define psmouse_fmt(fmt) KBUILD_BASENAME ": " fmt
#endif
#define psmouse_dbg(psmouse, format, ...) \
dev_dbg(&(psmouse)->ps2dev.serio->dev, \
psmouse_fmt(format), ##__VA_ARGS__)
#define psmouse_info(psmouse, format, ...) \
dev_info(&(psmouse)->ps2dev.serio->dev, \
psmouse_fmt(format), ##__VA_ARGS__)
#define psmouse_warn(psmouse, format, ...) \
dev_warn(&(psmouse)->ps2dev.serio->dev, \
psmouse_fmt(format), ##__VA_ARGS__)
#define psmouse_err(psmouse, format, ...) \
dev_err(&(psmouse)->ps2dev.serio->dev, \
psmouse_fmt(format), ##__VA_ARGS__)
#define psmouse_notice(psmouse, format, ...) \
dev_notice(&(psmouse)->ps2dev.serio->dev, \
psmouse_fmt(format), ##__VA_ARGS__)
#define psmouse_printk(level, psmouse, format, ...) \
dev_printk(level, \
&(psmouse)->ps2dev.serio->dev, \
psmouse_fmt(format), ##__VA_ARGS__)
#endif /* _PSMOUSE_H */

View file

@ -183,7 +183,7 @@ static int __devinit pxa930_trkball_probe(struct platform_device *pdev)
/* held the module in reset, will be enabled in open() */
pxa930_trkball_disable(trkball);
error = request_irq(irq, pxa930_trkball_interrupt, IRQF_DISABLED,
error = request_irq(irq, pxa930_trkball_interrupt, 0,
pdev->name, trkball);
if (error) {
dev_err(&pdev->dev, "failed to request irq: %d\n", error);

View file

@ -607,11 +607,12 @@ static void fsp_packet_debug(unsigned char packet[])
ps2_packet_cnt++;
jiffies_msec = jiffies_to_msecs(jiffies);
printk(KERN_DEBUG "%08dms PS/2 packets: %02x, %02x, %02x, %02x\n",
jiffies_msec, packet[0], packet[1], packet[2], packet[3]);
psmouse_dbg(psmouse,
"%08dms PS/2 packets: %02x, %02x, %02x, %02x\n",
jiffies_msec, packet[0], packet[1], packet[2], packet[3]);
if (jiffies_msec - ps2_last_second > 1000) {
printk(KERN_DEBUG "PS/2 packets/sec = %d\n", ps2_packet_cnt);
psmouse_dbg(psmouse, "PS/2 packets/sec = %d\n", ps2_packet_cnt);
ps2_packet_cnt = 0;
ps2_last_second = jiffies_msec;
}
@ -820,9 +821,9 @@ int fsp_init(struct psmouse *psmouse)
return -ENODEV;
}
printk(KERN_INFO
"Finger Sensing Pad, hw: %d.%d.%d, sw: %s, buttons: %d\n",
ver >> 4, ver & 0x0F, rev, fsp_drv_ver, buttons & 7);
psmouse_info(psmouse,
"Finger Sensing Pad, hw: %d.%d.%d, sw: %s, buttons: %d\n",
ver >> 4, ver & 0x0F, rev, fsp_drv_ver, buttons & 7);
psmouse->private = priv = kzalloc(sizeof(struct fsp_data), GFP_KERNEL);
if (!priv)

View file

@ -44,6 +44,16 @@
#define YMIN_NOMINAL 1408
#define YMAX_NOMINAL 4448
/*
* Synaptics touchpads report the y coordinate from bottom to top, which is
* opposite from what userspace expects.
* This function is used to invert y before reporting.
*/
static int synaptics_invert_y(int y)
{
return YMAX_NOMINAL + YMIN_NOMINAL - y;
}
/*****************************************************************************
* Stuff we need even when we do not want native Synaptics support
@ -157,8 +167,8 @@ static int synaptics_capability(struct psmouse *psmouse)
if (SYN_EXT_CAP_REQUESTS(priv->capabilities) >= 1) {
if (synaptics_send_cmd(psmouse, SYN_QUE_EXT_CAPAB, cap)) {
printk(KERN_ERR "Synaptics claims to have extended capabilities,"
" but I'm not able to read them.\n");
psmouse_warn(psmouse,
"device claims to have extended capabilities, but I'm not able to read them.\n");
} else {
priv->ext_cap = (cap[0] << 16) | (cap[1] << 8) | cap[2];
@ -173,8 +183,8 @@ static int synaptics_capability(struct psmouse *psmouse)
if (SYN_EXT_CAP_REQUESTS(priv->capabilities) >= 4) {
if (synaptics_send_cmd(psmouse, SYN_QUE_EXT_CAPAB_0C, cap)) {
printk(KERN_ERR "Synaptics claims to have extended capability 0x0c,"
" but I'm not able to read it.\n");
psmouse_warn(psmouse,
"device claims to have extended capability 0x0c, but I'm not able to read it.\n");
} else {
priv->ext_cap_0c = (cap[0] << 16) | (cap[1] << 8) | cap[2];
}
@ -222,8 +232,8 @@ static int synaptics_resolution(struct psmouse *psmouse)
if (SYN_EXT_CAP_REQUESTS(priv->capabilities) >= 5 &&
SYN_CAP_MAX_DIMENSIONS(priv->ext_cap_0c)) {
if (synaptics_send_cmd(psmouse, SYN_QUE_EXT_MAX_COORDS, resp)) {
printk(KERN_ERR "Synaptics claims to have max coordinates"
" query, but I'm not able to read it.\n");
psmouse_warn(psmouse,
"device claims to have max coordinates query, but I'm not able to read it.\n");
} else {
priv->x_max = (resp[0] << 5) | ((resp[1] & 0x0f) << 1);
priv->y_max = (resp[2] << 5) | ((resp[1] & 0xf0) >> 3);
@ -233,8 +243,8 @@ static int synaptics_resolution(struct psmouse *psmouse)
if (SYN_EXT_CAP_REQUESTS(priv->capabilities) >= 7 &&
SYN_CAP_MIN_DIMENSIONS(priv->ext_cap_0c)) {
if (synaptics_send_cmd(psmouse, SYN_QUE_EXT_MIN_COORDS, resp)) {
printk(KERN_ERR "Synaptics claims to have min coordinates"
" query, but I'm not able to read it.\n");
psmouse_warn(psmouse,
"device claims to have min coordinates query, but I'm not able to read it.\n");
} else {
priv->x_min = (resp[0] << 5) | ((resp[1] & 0x0f) << 1);
priv->y_min = (resp[2] << 5) | ((resp[1] & 0xf0) >> 3);
@ -294,7 +304,8 @@ static int synaptics_set_advanced_gesture_mode(struct psmouse *psmouse)
static unsigned char param = 0xc8;
struct synaptics_data *priv = psmouse->private;
if (!SYN_CAP_ADV_GESTURE(priv->ext_cap_0c))
if (!(SYN_CAP_ADV_GESTURE(priv->ext_cap_0c) ||
SYN_CAP_IMAGE_SENSOR(priv->ext_cap_0c)))
return 0;
if (psmouse_sliced_command(psmouse, SYN_QUE_MODEL))
@ -377,7 +388,8 @@ static void synaptics_pt_activate(struct psmouse *psmouse)
priv->mode &= ~SYN_BIT_FOUR_BYTE_CLIENT;
if (synaptics_mode_cmd(psmouse, priv->mode))
printk(KERN_INFO "synaptics: failed to switch guest protocol\n");
psmouse_warn(psmouse,
"failed to switch guest protocol\n");
}
}
@ -387,7 +399,8 @@ static void synaptics_pt_create(struct psmouse *psmouse)
serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
if (!serio) {
printk(KERN_ERR "synaptics: not enough memory to allocate pass-through port\n");
psmouse_err(psmouse,
"not enough memory for pass-through port\n");
return;
}
@ -401,7 +414,8 @@ static void synaptics_pt_create(struct psmouse *psmouse)
psmouse->pt_activate = synaptics_pt_activate;
printk(KERN_INFO "serio: %s port at %s\n", serio->name, psmouse->phys);
psmouse_info(psmouse, "serio: %s port at %s\n",
serio->name, psmouse->phys);
serio_register_port(serio);
}
@ -409,6 +423,44 @@ static void synaptics_pt_create(struct psmouse *psmouse)
* Functions to interpret the absolute mode packets
****************************************************************************/
static void synaptics_mt_state_set(struct synaptics_mt_state *state, int count,
int sgm, int agm)
{
state->count = count;
state->sgm = sgm;
state->agm = agm;
}
static void synaptics_parse_agm(const unsigned char buf[],
struct synaptics_data *priv,
struct synaptics_hw_state *hw)
{
struct synaptics_hw_state *agm = &priv->agm;
int agm_packet_type;
agm_packet_type = (buf[5] & 0x30) >> 4;
switch (agm_packet_type) {
case 1:
/* Gesture packet: (x, y, z) half resolution */
agm->w = hw->w;
agm->x = (((buf[4] & 0x0f) << 8) | buf[1]) << 1;
agm->y = (((buf[4] & 0xf0) << 4) | buf[2]) << 1;
agm->z = ((buf[3] & 0x30) | (buf[5] & 0x0f)) << 1;
break;
case 2:
/* AGM-CONTACT packet: (count, sgm, agm) */
synaptics_mt_state_set(&agm->mt_state, buf[1], buf[2], buf[4]);
break;
default:
break;
}
/* Record that at least one AGM has been received since last SGM */
priv->agm_pending = true;
}
static int synaptics_parse_hw_state(const unsigned char buf[],
struct synaptics_data *priv,
struct synaptics_hw_state *hw)
@ -442,11 +494,10 @@ static int synaptics_parse_hw_state(const unsigned char buf[],
hw->down = ((buf[0] ^ buf[3]) & 0x02) ? 1 : 0;
}
if (SYN_CAP_ADV_GESTURE(priv->ext_cap_0c) && hw->w == 2) {
/* Gesture packet: (x, y, z) at half resolution */
priv->mt.x = (((buf[4] & 0x0f) << 8) | buf[1]) << 1;
priv->mt.y = (((buf[4] & 0xf0) << 4) | buf[2]) << 1;
priv->mt.z = ((buf[3] & 0x30) | (buf[5] & 0x0f)) << 1;
if ((SYN_CAP_ADV_GESTURE(priv->ext_cap_0c) ||
SYN_CAP_IMAGE_SENSOR(priv->ext_cap_0c)) &&
hw->w == 2) {
synaptics_parse_agm(buf, priv, hw);
return 1;
}
@ -502,8 +553,7 @@ static void synaptics_report_semi_mt_slot(struct input_dev *dev, int slot,
input_mt_report_slot_state(dev, MT_TOOL_FINGER, active);
if (active) {
input_report_abs(dev, ABS_MT_POSITION_X, x);
input_report_abs(dev, ABS_MT_POSITION_Y,
YMAX_NOMINAL + YMIN_NOMINAL - y);
input_report_abs(dev, ABS_MT_POSITION_Y, synaptics_invert_y(y));
}
}
@ -526,6 +576,388 @@ static void synaptics_report_semi_mt_data(struct input_dev *dev,
}
}
static void synaptics_report_buttons(struct psmouse *psmouse,
const struct synaptics_hw_state *hw)
{
struct input_dev *dev = psmouse->dev;
struct synaptics_data *priv = psmouse->private;
int i;
input_report_key(dev, BTN_LEFT, hw->left);
input_report_key(dev, BTN_RIGHT, hw->right);
if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities))
input_report_key(dev, BTN_MIDDLE, hw->middle);
if (SYN_CAP_FOUR_BUTTON(priv->capabilities)) {
input_report_key(dev, BTN_FORWARD, hw->up);
input_report_key(dev, BTN_BACK, hw->down);
}
for (i = 0; i < SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap); i++)
input_report_key(dev, BTN_0 + i, hw->ext_buttons & (1 << i));
}
static void synaptics_report_slot(struct input_dev *dev, int slot,
const struct synaptics_hw_state *hw)
{
input_mt_slot(dev, slot);
input_mt_report_slot_state(dev, MT_TOOL_FINGER, (hw != NULL));
if (!hw)
return;
input_report_abs(dev, ABS_MT_POSITION_X, hw->x);
input_report_abs(dev, ABS_MT_POSITION_Y, synaptics_invert_y(hw->y));
input_report_abs(dev, ABS_MT_PRESSURE, hw->z);
}
static void synaptics_report_mt_data(struct psmouse *psmouse,
struct synaptics_mt_state *mt_state,
const struct synaptics_hw_state *sgm)
{
struct input_dev *dev = psmouse->dev;
struct synaptics_data *priv = psmouse->private;
struct synaptics_hw_state *agm = &priv->agm;
struct synaptics_mt_state *old = &priv->mt_state;
switch (mt_state->count) {
case 0:
synaptics_report_slot(dev, 0, NULL);
synaptics_report_slot(dev, 1, NULL);
break;
case 1:
if (mt_state->sgm == -1) {
synaptics_report_slot(dev, 0, NULL);
synaptics_report_slot(dev, 1, NULL);
} else if (mt_state->sgm == 0) {
synaptics_report_slot(dev, 0, sgm);
synaptics_report_slot(dev, 1, NULL);
} else {
synaptics_report_slot(dev, 0, NULL);
synaptics_report_slot(dev, 1, sgm);
}
break;
default:
/*
* If the finger slot contained in SGM is valid, and either
* hasn't changed, or is new, then report SGM in MTB slot 0.
* Otherwise, empty MTB slot 0.
*/
if (mt_state->sgm != -1 &&
(mt_state->sgm == old->sgm || old->sgm == -1))
synaptics_report_slot(dev, 0, sgm);
else
synaptics_report_slot(dev, 0, NULL);
/*
* If the finger slot contained in AGM is valid, and either
* hasn't changed, or is new, then report AGM in MTB slot 1.
* Otherwise, empty MTB slot 1.
*/
if (mt_state->agm != -1 &&
(mt_state->agm == old->agm || old->agm == -1))
synaptics_report_slot(dev, 1, agm);
else
synaptics_report_slot(dev, 1, NULL);
break;
}
/* Don't use active slot count to generate BTN_TOOL events. */
input_mt_report_pointer_emulation(dev, false);
/* Send the number of fingers reported by touchpad itself. */
input_mt_report_finger_count(dev, mt_state->count);
synaptics_report_buttons(psmouse, sgm);
input_sync(dev);
}
/* Handle case where mt_state->count = 0 */
static void synaptics_image_sensor_0f(struct synaptics_data *priv,
struct synaptics_mt_state *mt_state)
{
synaptics_mt_state_set(mt_state, 0, -1, -1);
priv->mt_state_lost = false;
}
/* Handle case where mt_state->count = 1 */
static void synaptics_image_sensor_1f(struct synaptics_data *priv,
struct synaptics_mt_state *mt_state)
{
struct synaptics_hw_state *agm = &priv->agm;
struct synaptics_mt_state *old = &priv->mt_state;
/*
* If the last AGM was (0,0,0), and there is only one finger left,
* then we absolutely know that SGM contains slot 0, and all other
* fingers have been removed.
*/
if (priv->agm_pending && agm->z == 0) {
synaptics_mt_state_set(mt_state, 1, 0, -1);
priv->mt_state_lost = false;
return;
}
switch (old->count) {
case 0:
synaptics_mt_state_set(mt_state, 1, 0, -1);
break;
case 1:
/*
* If mt_state_lost, then the previous transition was 3->1,
* and SGM now contains either slot 0 or 1, but we don't know
* which. So, we just assume that the SGM now contains slot 1.
*
* If pending AGM and either:
* (a) the previous SGM slot contains slot 0, or
* (b) there was no SGM slot
* then, the SGM now contains slot 1
*
* Case (a) happens with very rapid "drum roll" gestures, where
* slot 0 finger is lifted and a new slot 1 finger touches
* within one reporting interval.
*
* Case (b) happens if initially two or more fingers tap
* briefly, and all but one lift before the end of the first
* reporting interval.
*
* (In both these cases, slot 0 will becomes empty, so SGM
* contains slot 1 with the new finger)
*
* Else, if there was no previous SGM, it now contains slot 0.
*
* Otherwise, SGM still contains the same slot.
*/
if (priv->mt_state_lost ||
(priv->agm_pending && old->sgm <= 0))
synaptics_mt_state_set(mt_state, 1, 1, -1);
else if (old->sgm == -1)
synaptics_mt_state_set(mt_state, 1, 0, -1);
break;
case 2:
/*
* If mt_state_lost, we don't know which finger SGM contains.
*
* So, report 1 finger, but with both slots empty.
* We will use slot 1 on subsequent 1->1
*/
if (priv->mt_state_lost) {
synaptics_mt_state_set(mt_state, 1, -1, -1);
break;
}
/*
* Since the last AGM was NOT (0,0,0), it was the finger in
* slot 0 that has been removed.
* So, SGM now contains previous AGM's slot, and AGM is now
* empty.
*/
synaptics_mt_state_set(mt_state, 1, old->agm, -1);
break;
case 3:
/*
* Since last AGM was not (0,0,0), we don't know which finger
* is left.
*
* So, report 1 finger, but with both slots empty.
* We will use slot 1 on subsequent 1->1
*/
synaptics_mt_state_set(mt_state, 1, -1, -1);
priv->mt_state_lost = true;
break;
case 4:
case 5:
/* mt_state was updated by AGM-CONTACT packet */
break;
}
}
/* Handle case where mt_state->count = 2 */
static void synaptics_image_sensor_2f(struct synaptics_data *priv,
struct synaptics_mt_state *mt_state)
{
struct synaptics_mt_state *old = &priv->mt_state;
switch (old->count) {
case 0:
synaptics_mt_state_set(mt_state, 2, 0, 1);
break;
case 1:
/*
* If previous SGM contained slot 1 or higher, SGM now contains
* slot 0 (the newly touching finger) and AGM contains SGM's
* previous slot.
*
* Otherwise, SGM still contains slot 0 and AGM now contains
* slot 1.
*/
if (old->sgm >= 1)
synaptics_mt_state_set(mt_state, 2, 0, old->sgm);
else
synaptics_mt_state_set(mt_state, 2, 0, 1);
break;
case 2:
/*
* If mt_state_lost, SGM now contains either finger 1 or 2, but
* we don't know which.
* So, we just assume that the SGM contains slot 0 and AGM 1.
*/
if (priv->mt_state_lost)
synaptics_mt_state_set(mt_state, 2, 0, 1);
/*
* Otherwise, use the same mt_state, since it either hasn't
* changed, or was updated by a recently received AGM-CONTACT
* packet.
*/
break;
case 3:
/*
* 3->2 transitions have two unsolvable problems:
* 1) no indication is given which finger was removed
* 2) no way to tell if agm packet was for finger 3
* before 3->2, or finger 2 after 3->2.
*
* So, report 2 fingers, but empty all slots.
* We will guess slots [0,1] on subsequent 2->2.
*/
synaptics_mt_state_set(mt_state, 2, -1, -1);
priv->mt_state_lost = true;
break;
case 4:
case 5:
/* mt_state was updated by AGM-CONTACT packet */
break;
}
}
/* Handle case where mt_state->count = 3 */
static void synaptics_image_sensor_3f(struct synaptics_data *priv,
struct synaptics_mt_state *mt_state)
{
struct synaptics_mt_state *old = &priv->mt_state;
switch (old->count) {
case 0:
synaptics_mt_state_set(mt_state, 3, 0, 2);
break;
case 1:
/*
* If previous SGM contained slot 2 or higher, SGM now contains
* slot 0 (one of the newly touching fingers) and AGM contains
* SGM's previous slot.
*
* Otherwise, SGM now contains slot 0 and AGM contains slot 2.
*/
if (old->sgm >= 2)
synaptics_mt_state_set(mt_state, 3, 0, old->sgm);
else
synaptics_mt_state_set(mt_state, 3, 0, 2);
break;
case 2:
/*
* If the AGM previously contained slot 3 or higher, then the
* newly touching finger is in the lowest available slot.
*
* If SGM was previously 1 or higher, then the new SGM is
* now slot 0 (with a new finger), otherwise, the new finger
* is now in a hidden slot between 0 and AGM's slot.
*
* In all such cases, the SGM now contains slot 0, and the AGM
* continues to contain the same slot as before.
*/
if (old->agm >= 3) {
synaptics_mt_state_set(mt_state, 3, 0, old->agm);
break;
}
/*
* After some 3->1 and all 3->2 transitions, we lose track
* of which slot is reported by SGM and AGM.
*
* For 2->3 in this state, report 3 fingers, but empty all
* slots, and we will guess (0,2) on a subsequent 0->3.
*
* To userspace, the resulting transition will look like:
* 2:[0,1] -> 3:[-1,-1] -> 3:[0,2]
*/
if (priv->mt_state_lost) {
synaptics_mt_state_set(mt_state, 3, -1, -1);
break;
}
/*
* If the (SGM,AGM) really previously contained slots (0, 1),
* then we cannot know what slot was just reported by the AGM,
* because the 2->3 transition can occur either before or after
* the AGM packet. Thus, this most recent AGM could contain
* either the same old slot 1 or the new slot 2.
* Subsequent AGMs will be reporting slot 2.
*
* To userspace, the resulting transition will look like:
* 2:[0,1] -> 3:[0,-1] -> 3:[0,2]
*/
synaptics_mt_state_set(mt_state, 3, 0, -1);
break;
case 3:
/*
* If, for whatever reason, the previous agm was invalid,
* Assume SGM now contains slot 0, AGM now contains slot 2.
*/
if (old->agm <= 2)
synaptics_mt_state_set(mt_state, 3, 0, 2);
/*
* mt_state either hasn't changed, or was updated by a recently
* received AGM-CONTACT packet.
*/
break;
case 4:
case 5:
/* mt_state was updated by AGM-CONTACT packet */
break;
}
}
/* Handle case where mt_state->count = 4, or = 5 */
static void synaptics_image_sensor_45f(struct synaptics_data *priv,
struct synaptics_mt_state *mt_state)
{
/* mt_state was updated correctly by AGM-CONTACT packet */
priv->mt_state_lost = false;
}
static void synaptics_image_sensor_process(struct psmouse *psmouse,
struct synaptics_hw_state *sgm)
{
struct synaptics_data *priv = psmouse->private;
struct synaptics_hw_state *agm = &priv->agm;
struct synaptics_mt_state mt_state;
/* Initialize using current mt_state (as updated by last agm) */
mt_state = agm->mt_state;
/*
* Update mt_state using the new finger count and current mt_state.
*/
if (sgm->z == 0)
synaptics_image_sensor_0f(priv, &mt_state);
else if (sgm->w >= 4)
synaptics_image_sensor_1f(priv, &mt_state);
else if (sgm->w == 0)
synaptics_image_sensor_2f(priv, &mt_state);
else if (sgm->w == 1 && mt_state.count <= 3)
synaptics_image_sensor_3f(priv, &mt_state);
else
synaptics_image_sensor_45f(priv, &mt_state);
/* Send resulting input events to user space */
synaptics_report_mt_data(psmouse, &mt_state, sgm);
/* Store updated mt_state */
priv->mt_state = agm->mt_state = mt_state;
priv->agm_pending = false;
}
/*
* called for each full received packet from the touchpad
*/
@ -536,11 +968,15 @@ static void synaptics_process_packet(struct psmouse *psmouse)
struct synaptics_hw_state hw;
int num_fingers;
int finger_width;
int i;
if (synaptics_parse_hw_state(psmouse->packet, priv, &hw))
return;
if (SYN_CAP_IMAGE_SENSOR(priv->ext_cap_0c)) {
synaptics_image_sensor_process(psmouse, &hw);
return;
}
if (hw.scroll) {
priv->scroll += hw.scroll;
@ -586,7 +1022,8 @@ static void synaptics_process_packet(struct psmouse *psmouse)
}
if (SYN_CAP_ADV_GESTURE(priv->ext_cap_0c))
synaptics_report_semi_mt_data(dev, &hw, &priv->mt, num_fingers);
synaptics_report_semi_mt_data(dev, &hw, &priv->agm,
num_fingers);
/* Post events
* BTN_TOUCH has to be first as mousedev relies on it when doing
@ -597,7 +1034,7 @@ static void synaptics_process_packet(struct psmouse *psmouse)
if (num_fingers > 0) {
input_report_abs(dev, ABS_X, hw.x);
input_report_abs(dev, ABS_Y, YMAX_NOMINAL + YMIN_NOMINAL - hw.y);
input_report_abs(dev, ABS_Y, synaptics_invert_y(hw.y));
}
input_report_abs(dev, ABS_PRESSURE, hw.z);
@ -605,35 +1042,25 @@ static void synaptics_process_packet(struct psmouse *psmouse)
input_report_abs(dev, ABS_TOOL_WIDTH, finger_width);
input_report_key(dev, BTN_TOOL_FINGER, num_fingers == 1);
input_report_key(dev, BTN_LEFT, hw.left);
input_report_key(dev, BTN_RIGHT, hw.right);
if (SYN_CAP_MULTIFINGER(priv->capabilities)) {
input_report_key(dev, BTN_TOOL_DOUBLETAP, num_fingers == 2);
input_report_key(dev, BTN_TOOL_TRIPLETAP, num_fingers == 3);
}
if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities))
input_report_key(dev, BTN_MIDDLE, hw.middle);
if (SYN_CAP_FOUR_BUTTON(priv->capabilities)) {
input_report_key(dev, BTN_FORWARD, hw.up);
input_report_key(dev, BTN_BACK, hw.down);
}
for (i = 0; i < SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap); i++)
input_report_key(dev, BTN_0 + i, hw.ext_buttons & (1 << i));
synaptics_report_buttons(psmouse, &hw);
input_sync(dev);
}
static int synaptics_validate_byte(unsigned char packet[], int idx, unsigned char pkt_type)
static int synaptics_validate_byte(struct psmouse *psmouse,
int idx, unsigned char pkt_type)
{
static const unsigned char newabs_mask[] = { 0xC8, 0x00, 0x00, 0xC8, 0x00 };
static const unsigned char newabs_rel_mask[] = { 0xC0, 0x00, 0x00, 0xC0, 0x00 };
static const unsigned char newabs_rslt[] = { 0x80, 0x00, 0x00, 0xC0, 0x00 };
static const unsigned char oldabs_mask[] = { 0xC0, 0x60, 0x00, 0xC0, 0x60 };
static const unsigned char oldabs_rslt[] = { 0xC0, 0x00, 0x00, 0x80, 0x00 };
const char *packet = psmouse->packet;
if (idx < 0 || idx > 4)
return 0;
@ -651,7 +1078,7 @@ static int synaptics_validate_byte(unsigned char packet[], int idx, unsigned cha
return (packet[idx] & oldabs_mask[idx]) == oldabs_rslt[idx];
default:
printk(KERN_ERR "synaptics: unknown packet type %d\n", pkt_type);
psmouse_err(psmouse, "unknown packet type %d\n", pkt_type);
return 0;
}
}
@ -661,8 +1088,8 @@ static unsigned char synaptics_detect_pkt_type(struct psmouse *psmouse)
int i;
for (i = 0; i < 5; i++)
if (!synaptics_validate_byte(psmouse->packet, i, SYN_NEWABS_STRICT)) {
printk(KERN_INFO "synaptics: using relaxed packet validation\n");
if (!synaptics_validate_byte(psmouse, i, SYN_NEWABS_STRICT)) {
psmouse_info(psmouse, "using relaxed packet validation\n");
return SYN_NEWABS_RELAXED;
}
@ -687,46 +1114,56 @@ static psmouse_ret_t synaptics_process_byte(struct psmouse *psmouse)
return PSMOUSE_FULL_PACKET;
}
return synaptics_validate_byte(psmouse->packet, psmouse->pktcnt - 1, priv->pkt_type) ?
return synaptics_validate_byte(psmouse, psmouse->pktcnt - 1, priv->pkt_type) ?
PSMOUSE_GOOD_DATA : PSMOUSE_BAD_DATA;
}
/*****************************************************************************
* Driver initialization/cleanup functions
****************************************************************************/
static void set_abs_position_params(struct input_dev *dev,
struct synaptics_data *priv, int x_code,
int y_code)
{
int x_min = priv->x_min ?: XMIN_NOMINAL;
int x_max = priv->x_max ?: XMAX_NOMINAL;
int y_min = priv->y_min ?: YMIN_NOMINAL;
int y_max = priv->y_max ?: YMAX_NOMINAL;
int fuzz = SYN_CAP_REDUCED_FILTERING(priv->ext_cap_0c) ?
SYN_REDUCED_FILTER_FUZZ : 0;
input_set_abs_params(dev, x_code, x_min, x_max, fuzz, 0);
input_set_abs_params(dev, y_code, y_min, y_max, fuzz, 0);
input_abs_set_res(dev, x_code, priv->x_res);
input_abs_set_res(dev, y_code, priv->y_res);
}
static void set_input_params(struct input_dev *dev, struct synaptics_data *priv)
{
int i;
int fuzz = SYN_CAP_REDUCED_FILTERING(priv->ext_cap_0c) ?
SYN_REDUCED_FILTER_FUZZ : 0;
__set_bit(INPUT_PROP_POINTER, dev->propbit);
__set_bit(EV_ABS, dev->evbit);
input_set_abs_params(dev, ABS_X,
priv->x_min ?: XMIN_NOMINAL,
priv->x_max ?: XMAX_NOMINAL,
fuzz, 0);
input_set_abs_params(dev, ABS_Y,
priv->y_min ?: YMIN_NOMINAL,
priv->y_max ?: YMAX_NOMINAL,
fuzz, 0);
set_abs_position_params(dev, priv, ABS_X, ABS_Y);
input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0);
if (SYN_CAP_ADV_GESTURE(priv->ext_cap_0c)) {
if (SYN_CAP_IMAGE_SENSOR(priv->ext_cap_0c)) {
input_mt_init_slots(dev, 2);
set_abs_position_params(dev, priv, ABS_MT_POSITION_X,
ABS_MT_POSITION_Y);
/* Image sensors can report per-contact pressure */
input_set_abs_params(dev, ABS_MT_PRESSURE, 0, 255, 0, 0);
/* Image sensors can signal 4 and 5 finger clicks */
__set_bit(BTN_TOOL_QUADTAP, dev->keybit);
__set_bit(BTN_TOOL_QUINTTAP, dev->keybit);
} else if (SYN_CAP_ADV_GESTURE(priv->ext_cap_0c)) {
/* Non-image sensors with AGM use semi-mt */
__set_bit(INPUT_PROP_SEMI_MT, dev->propbit);
input_mt_init_slots(dev, 2);
input_set_abs_params(dev, ABS_MT_POSITION_X,
priv->x_min ?: XMIN_NOMINAL,
priv->x_max ?: XMAX_NOMINAL,
fuzz, 0);
input_set_abs_params(dev, ABS_MT_POSITION_Y,
priv->y_min ?: YMIN_NOMINAL,
priv->y_max ?: YMAX_NOMINAL,
fuzz, 0);
input_abs_set_res(dev, ABS_MT_POSITION_X, priv->x_res);
input_abs_set_res(dev, ABS_MT_POSITION_Y, priv->y_res);
set_abs_position_params(dev, priv, ABS_MT_POSITION_X,
ABS_MT_POSITION_Y);
}
if (SYN_CAP_PALMDETECT(priv->capabilities))
@ -759,9 +1196,6 @@ static void set_input_params(struct input_dev *dev, struct synaptics_data *priv)
__clear_bit(REL_X, dev->relbit);
__clear_bit(REL_Y, dev->relbit);
input_abs_set_res(dev, ABS_X, priv->x_res);
input_abs_set_res(dev, ABS_Y, priv->y_res);
if (SYN_CAP_CLICKPAD(priv->ext_cap_0c)) {
__set_bit(INPUT_PROP_BUTTONPAD, dev->propbit);
/* Clickpads report only left button */
@ -793,21 +1227,21 @@ static int synaptics_reconnect(struct psmouse *psmouse)
return -1;
if (retry > 1)
printk(KERN_DEBUG "Synaptics reconnected after %d tries\n",
retry);
psmouse_dbg(psmouse, "reconnected after %d tries\n", retry);
if (synaptics_query_hardware(psmouse)) {
printk(KERN_ERR "Unable to query Synaptics hardware.\n");
psmouse_err(psmouse, "Unable to query device.\n");
return -1;
}
if (synaptics_set_absolute_mode(psmouse)) {
printk(KERN_ERR "Unable to initialize Synaptics hardware.\n");
psmouse_err(psmouse, "Unable to initialize device.\n");
return -1;
}
if (synaptics_set_advanced_gesture_mode(psmouse)) {
printk(KERN_ERR "Advanced gesture mode reconnect failed.\n");
psmouse_err(psmouse,
"Advanced gesture mode reconnect failed.\n");
return -1;
}
@ -815,12 +1249,12 @@ static int synaptics_reconnect(struct psmouse *psmouse)
old_priv.model_id != priv->model_id ||
old_priv.capabilities != priv->capabilities ||
old_priv.ext_cap != priv->ext_cap) {
printk(KERN_ERR "Synaptics hardware appears to be different: "
"id(%ld-%ld), model(%ld-%ld), caps(%lx-%lx), ext(%lx-%lx).\n",
old_priv.identity, priv->identity,
old_priv.model_id, priv->model_id,
old_priv.capabilities, priv->capabilities,
old_priv.ext_cap, priv->ext_cap);
psmouse_err(psmouse,
"hardware appears to be different: id(%ld-%ld), model(%ld-%ld), caps(%lx-%lx), ext(%lx-%lx).\n",
old_priv.identity, priv->identity,
old_priv.model_id, priv->model_id,
old_priv.capabilities, priv->capabilities,
old_priv.ext_cap, priv->ext_cap);
return -1;
}
@ -901,7 +1335,8 @@ int synaptics_init(struct psmouse *psmouse)
* just fine.
*/
if (broken_olpc_ec) {
printk(KERN_INFO "synaptics: OLPC XO detected, not enabling Synaptics protocol.\n");
psmouse_info(psmouse,
"OLPC XO detected, not enabling Synaptics protocol.\n");
return -ENODEV;
}
@ -912,26 +1347,28 @@ int synaptics_init(struct psmouse *psmouse)
psmouse_reset(psmouse);
if (synaptics_query_hardware(psmouse)) {
printk(KERN_ERR "Unable to query Synaptics hardware.\n");
psmouse_err(psmouse, "Unable to query device.\n");
goto init_fail;
}
if (synaptics_set_absolute_mode(psmouse)) {
printk(KERN_ERR "Unable to initialize Synaptics hardware.\n");
psmouse_err(psmouse, "Unable to initialize device.\n");
goto init_fail;
}
if (synaptics_set_advanced_gesture_mode(psmouse)) {
printk(KERN_ERR "Advanced gesture mode init failed.\n");
psmouse_err(psmouse, "Advanced gesture mode init failed.\n");
goto init_fail;
}
priv->pkt_type = SYN_MODEL_NEWABS(priv->model_id) ? SYN_NEWABS : SYN_OLDABS;
printk(KERN_INFO "Synaptics Touchpad, model: %ld, fw: %ld.%ld, id: %#lx, caps: %#lx/%#lx/%#lx\n",
SYN_ID_MODEL(priv->identity),
SYN_ID_MAJOR(priv->identity), SYN_ID_MINOR(priv->identity),
priv->model_id, priv->capabilities, priv->ext_cap, priv->ext_cap_0c);
psmouse_info(psmouse,
"Touchpad model: %ld, fw: %ld.%ld, id: %#lx, caps: %#lx/%#lx/%#lx\n",
SYN_ID_MODEL(priv->identity),
SYN_ID_MAJOR(priv->identity), SYN_ID_MINOR(priv->identity),
priv->model_id,
priv->capabilities, priv->ext_cap, priv->ext_cap_0c);
set_input_params(psmouse->dev, priv);
@ -963,8 +1400,9 @@ int synaptics_init(struct psmouse *psmouse)
* the same rate as a standard PS/2 mouse).
*/
if (psmouse->rate >= 80 && impaired_toshiba_kbc) {
printk(KERN_INFO "synaptics: Toshiba %s detected, limiting rate to 40pps.\n",
dmi_get_system_info(DMI_PRODUCT_NAME));
psmouse_info(psmouse,
"Toshiba %s detected, limiting rate to 40pps.\n",
dmi_get_system_info(DMI_PRODUCT_NAME));
psmouse->rate = 40;
}

View file

@ -74,6 +74,8 @@
* 2 0x04 reduced filtering firmware does less filtering on
* position data, driver should watch
* for noise.
* 2 0x08 image sensor image sensor tracks 5 fingers, but only
* reports 2.
* 2 0x20 report min query 0x0f gives min coord reported
*/
#define SYN_CAP_CLICKPAD(ex0c) ((ex0c) & 0x100000) /* 1-button ClickPad */
@ -82,6 +84,7 @@
#define SYN_CAP_MIN_DIMENSIONS(ex0c) ((ex0c) & 0x002000)
#define SYN_CAP_ADV_GESTURE(ex0c) ((ex0c) & 0x080000)
#define SYN_CAP_REDUCED_FILTERING(ex0c) ((ex0c) & 0x000400)
#define SYN_CAP_IMAGE_SENSOR(ex0c) ((ex0c) & 0x000800)
/* synaptics modes query bits */
#define SYN_MODE_ABSOLUTE(m) ((m) & (1 << 7))
@ -111,10 +114,19 @@
/* amount to fuzz position data when touchpad reports reduced filtering */
#define SYN_REDUCED_FILTER_FUZZ 8
/*
* A structure to describe which internal touchpad finger slots are being
* reported in raw packets.
*/
struct synaptics_mt_state {
int count; /* num fingers being tracked */
int sgm; /* which slot is reported by sgm pkt */
int agm; /* which slot is reported by agm pkt*/
};
/*
* A structure to describe the state of the touchpad hardware (buttons and pad)
*/
struct synaptics_hw_state {
int x;
int y;
@ -127,6 +139,9 @@ struct synaptics_hw_state {
unsigned int down:1;
unsigned char ext_buttons;
signed char scroll;
/* As reported in last AGM-CONTACT packets */
struct synaptics_mt_state mt_state;
};
struct synaptics_data {
@ -146,7 +161,15 @@ struct synaptics_data {
struct serio *pt_port; /* Pass-through serio port */
struct synaptics_hw_state mt; /* current gesture packet */
struct synaptics_mt_state mt_state; /* Current mt finger state */
bool mt_state_lost; /* mt_state may be incorrect */
/*
* Last received Advanced Gesture Mode (AGM) packet. An AGM packet
* contains position data for a second contact, at half resolution.
*/
struct synaptics_hw_state agm;
bool agm_pending; /* new AGM packet received */
};
void synaptics_module_init(void);

View file

@ -570,7 +570,7 @@ static int __devinit synaptics_i2c_probe(struct i2c_client *client,
"Requesting IRQ: %d\n", touch->client->irq);
ret = request_irq(touch->client->irq, synaptics_i2c_irq,
IRQF_DISABLED|IRQ_TYPE_EDGE_FALLING,
IRQ_TYPE_EDGE_FALLING,
DRIVER_NAME, touch);
if (ret) {
dev_warn(&touch->client->dev,
@ -619,7 +619,7 @@ static int __devexit synaptics_i2c_remove(struct i2c_client *client)
return 0;
}
#ifdef CONFIG_PM
#ifdef CONFIG_PM_SLEEP
static int synaptics_i2c_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);

View file

@ -9,6 +9,7 @@
* the Free Software Foundation.
*/
#include <linux/kref.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/poll.h>
@ -33,15 +34,16 @@ struct serio_raw {
unsigned int tail, head;
char name[16];
unsigned int refcnt;
struct kref kref;
struct serio *serio;
struct miscdevice dev;
wait_queue_head_t wait;
struct list_head list;
struct list_head client_list;
struct list_head node;
bool dead;
};
struct serio_raw_list {
struct serio_raw_client {
struct fasync_struct *fasync;
struct serio_raw *serio_raw;
struct list_head node;
@ -49,7 +51,6 @@ struct serio_raw_list {
static DEFINE_MUTEX(serio_raw_mutex);
static LIST_HEAD(serio_raw_list);
static unsigned int serio_raw_no;
/*********************************************************************
* Interface with userspace (file operations) *
@ -57,9 +58,9 @@ static unsigned int serio_raw_no;
static int serio_raw_fasync(int fd, struct file *file, int on)
{
struct serio_raw_list *list = file->private_data;
struct serio_raw_client *client = file->private_data;
return fasync_helper(fd, file, on, &list->fasync);
return fasync_helper(fd, file, on, &client->fasync);
}
static struct serio_raw *serio_raw_locate(int minor)
@ -77,8 +78,8 @@ static struct serio_raw *serio_raw_locate(int minor)
static int serio_raw_open(struct inode *inode, struct file *file)
{
struct serio_raw *serio_raw;
struct serio_raw_list *list;
int retval = 0;
struct serio_raw_client *client;
int retval;
retval = mutex_lock_interruptible(&serio_raw_mutex);
if (retval)
@ -90,60 +91,61 @@ static int serio_raw_open(struct inode *inode, struct file *file)
goto out;
}
if (!serio_raw->serio) {
if (serio_raw->dead) {
retval = -ENODEV;
goto out;
}
list = kzalloc(sizeof(struct serio_raw_list), GFP_KERNEL);
if (!list) {
client = kzalloc(sizeof(struct serio_raw_client), GFP_KERNEL);
if (!client) {
retval = -ENOMEM;
goto out;
}
list->serio_raw = serio_raw;
file->private_data = list;
client->serio_raw = serio_raw;
file->private_data = client;
serio_raw->refcnt++;
list_add_tail(&list->node, &serio_raw->list);
kref_get(&serio_raw->kref);
serio_pause_rx(serio_raw->serio);
list_add_tail(&client->node, &serio_raw->client_list);
serio_continue_rx(serio_raw->serio);
out:
mutex_unlock(&serio_raw_mutex);
return retval;
}
static int serio_raw_cleanup(struct serio_raw *serio_raw)
static void serio_raw_free(struct kref *kref)
{
if (--serio_raw->refcnt == 0) {
misc_deregister(&serio_raw->dev);
list_del_init(&serio_raw->node);
kfree(serio_raw);
struct serio_raw *serio_raw =
container_of(kref, struct serio_raw, kref);
return 1;
}
return 0;
put_device(&serio_raw->serio->dev);
kfree(serio_raw);
}
static int serio_raw_release(struct inode *inode, struct file *file)
{
struct serio_raw_list *list = file->private_data;
struct serio_raw *serio_raw = list->serio_raw;
struct serio_raw_client *client = file->private_data;
struct serio_raw *serio_raw = client->serio_raw;
mutex_lock(&serio_raw_mutex);
serio_pause_rx(serio_raw->serio);
list_del(&client->node);
serio_continue_rx(serio_raw->serio);
serio_raw_cleanup(serio_raw);
kfree(client);
kref_put(&serio_raw->kref, serio_raw_free);
mutex_unlock(&serio_raw_mutex);
return 0;
}
static int serio_raw_fetch_byte(struct serio_raw *serio_raw, char *c)
static bool serio_raw_fetch_byte(struct serio_raw *serio_raw, char *c)
{
unsigned long flags;
int empty;
bool empty;
spin_lock_irqsave(&serio_raw->serio->lock, flags);
serio_pause_rx(serio_raw->serio);
empty = serio_raw->head == serio_raw->tail;
if (!empty) {
@ -151,30 +153,31 @@ static int serio_raw_fetch_byte(struct serio_raw *serio_raw, char *c)
serio_raw->tail = (serio_raw->tail + 1) % SERIO_RAW_QUEUE_LEN;
}
spin_unlock_irqrestore(&serio_raw->serio->lock, flags);
serio_continue_rx(serio_raw->serio);
return !empty;
}
static ssize_t serio_raw_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
static ssize_t serio_raw_read(struct file *file, char __user *buffer,
size_t count, loff_t *ppos)
{
struct serio_raw_list *list = file->private_data;
struct serio_raw *serio_raw = list->serio_raw;
struct serio_raw_client *client = file->private_data;
struct serio_raw *serio_raw = client->serio_raw;
char uninitialized_var(c);
ssize_t retval = 0;
if (!serio_raw->serio)
if (serio_raw->dead)
return -ENODEV;
if (serio_raw->head == serio_raw->tail && (file->f_flags & O_NONBLOCK))
return -EAGAIN;
retval = wait_event_interruptible(list->serio_raw->wait,
serio_raw->head != serio_raw->tail || !serio_raw->serio);
retval = wait_event_interruptible(serio_raw->wait,
serio_raw->head != serio_raw->tail || serio_raw->dead);
if (retval)
return retval;
if (!serio_raw->serio)
if (serio_raw->dead)
return -ENODEV;
while (retval < count && serio_raw_fetch_byte(serio_raw, &c)) {
@ -186,9 +189,11 @@ static ssize_t serio_raw_read(struct file *file, char __user *buffer, size_t cou
return retval;
}
static ssize_t serio_raw_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
static ssize_t serio_raw_write(struct file *file, const char __user *buffer,
size_t count, loff_t *ppos)
{
struct serio_raw_list *list = file->private_data;
struct serio_raw_client *client = file->private_data;
struct serio_raw *serio_raw = client->serio_raw;
ssize_t written = 0;
int retval;
unsigned char c;
@ -197,7 +202,7 @@ static ssize_t serio_raw_write(struct file *file, const char __user *buffer, siz
if (retval)
return retval;
if (!list->serio_raw->serio) {
if (serio_raw->dead) {
retval = -ENODEV;
goto out;
}
@ -210,7 +215,7 @@ static ssize_t serio_raw_write(struct file *file, const char __user *buffer, siz
retval = -EFAULT;
goto out;
}
if (serio_write(list->serio_raw->serio, c)) {
if (serio_write(serio_raw->serio, c)) {
retval = -EIO;
goto out;
}
@ -224,46 +229,49 @@ static ssize_t serio_raw_write(struct file *file, const char __user *buffer, siz
static unsigned int serio_raw_poll(struct file *file, poll_table *wait)
{
struct serio_raw_list *list = file->private_data;
struct serio_raw_client *client = file->private_data;
struct serio_raw *serio_raw = client->serio_raw;
unsigned int mask;
poll_wait(file, &list->serio_raw->wait, wait);
poll_wait(file, &serio_raw->wait, wait);
if (list->serio_raw->head != list->serio_raw->tail)
mask = serio_raw->dead ? POLLHUP | POLLERR : POLLOUT | POLLWRNORM;
if (serio_raw->head != serio_raw->tail)
return POLLIN | POLLRDNORM;
return 0;
}
static const struct file_operations serio_raw_fops = {
.owner = THIS_MODULE,
.open = serio_raw_open,
.release = serio_raw_release,
.read = serio_raw_read,
.write = serio_raw_write,
.poll = serio_raw_poll,
.fasync = serio_raw_fasync,
.llseek = noop_llseek,
.owner = THIS_MODULE,
.open = serio_raw_open,
.release = serio_raw_release,
.read = serio_raw_read,
.write = serio_raw_write,
.poll = serio_raw_poll,
.fasync = serio_raw_fasync,
.llseek = noop_llseek,
};
/*********************************************************************
* Interface with serio port *
* Interface with serio port *
*********************************************************************/
static irqreturn_t serio_raw_interrupt(struct serio *serio, unsigned char data,
unsigned int dfl)
{
struct serio_raw *serio_raw = serio_get_drvdata(serio);
struct serio_raw_list *list;
struct serio_raw_client *client;
unsigned int head = serio_raw->head;
/* we are holding serio->lock here so we are prootected */
/* we are holding serio->lock here so we are protected */
serio_raw->queue[head] = data;
head = (head + 1) % SERIO_RAW_QUEUE_LEN;
if (likely(head != serio_raw->tail)) {
serio_raw->head = head;
list_for_each_entry(list, &serio_raw->list, node)
kill_fasync(&list->fasync, SIGIO, POLL_IN);
list_for_each_entry(client, &serio_raw->client_list, node)
kill_fasync(&client->fasync, SIGIO, POLL_IN);
wake_up_interruptible(&serio_raw->wait);
}
@ -272,29 +280,37 @@ static irqreturn_t serio_raw_interrupt(struct serio *serio, unsigned char data,
static int serio_raw_connect(struct serio *serio, struct serio_driver *drv)
{
static atomic_t serio_raw_no = ATOMIC_INIT(0);
struct serio_raw *serio_raw;
int err;
if (!(serio_raw = kzalloc(sizeof(struct serio_raw), GFP_KERNEL))) {
printk(KERN_ERR "serio_raw.c: can't allocate memory for a device\n");
serio_raw = kzalloc(sizeof(struct serio_raw), GFP_KERNEL);
if (!serio_raw) {
dev_dbg(&serio->dev, "can't allocate memory for a device\n");
return -ENOMEM;
}
mutex_lock(&serio_raw_mutex);
snprintf(serio_raw->name, sizeof(serio_raw->name), "serio_raw%d", serio_raw_no++);
serio_raw->refcnt = 1;
serio_raw->serio = serio;
INIT_LIST_HEAD(&serio_raw->list);
snprintf(serio_raw->name, sizeof(serio_raw->name),
"serio_raw%ld", (long)atomic_inc_return(&serio_raw_no) - 1);
kref_init(&serio_raw->kref);
INIT_LIST_HEAD(&serio_raw->client_list);
init_waitqueue_head(&serio_raw->wait);
serio_raw->serio = serio;
get_device(&serio->dev);
serio_set_drvdata(serio, serio_raw);
err = serio_open(serio, drv);
if (err)
goto out_free;
goto err_free;
err = mutex_lock_killable(&serio_raw_mutex);
if (err)
goto err_close;
list_add_tail(&serio_raw->node, &serio_raw_list);
mutex_unlock(&serio_raw_mutex);
serio_raw->dev.minor = PSMOUSE_MINOR;
serio_raw->dev.name = serio_raw->name;
@ -308,23 +324,23 @@ static int serio_raw_connect(struct serio *serio, struct serio_driver *drv)
}
if (err) {
printk(KERN_INFO "serio_raw: failed to register raw access device for %s\n",
dev_err(&serio->dev,
"failed to register raw access device for %s\n",
serio->phys);
goto out_close;
goto err_unlink;
}
printk(KERN_INFO "serio_raw: raw access enabled on %s (%s, minor %d)\n",
serio->phys, serio_raw->name, serio_raw->dev.minor);
goto out;
dev_info(&serio->dev, "raw access enabled on %s (%s, minor %d)\n",
serio->phys, serio_raw->name, serio_raw->dev.minor);
return 0;
out_close:
serio_close(serio);
err_unlink:
list_del_init(&serio_raw->node);
out_free:
err_close:
serio_close(serio);
err_free:
serio_set_drvdata(serio, NULL);
kfree(serio_raw);
out:
mutex_unlock(&serio_raw_mutex);
kref_put(&serio_raw->kref, serio_raw_free);
return err;
}
@ -334,7 +350,8 @@ static int serio_raw_reconnect(struct serio *serio)
struct serio_driver *drv = serio->drv;
if (!drv || !serio_raw) {
printk(KERN_DEBUG "serio_raw: reconnect request, but serio is disconnected, ignoring...\n");
dev_dbg(&serio->dev,
"reconnect request, but serio is disconnected, ignoring...\n");
return -1;
}
@ -345,22 +362,40 @@ static int serio_raw_reconnect(struct serio *serio)
return 0;
}
/*
* Wake up users waiting for IO so they can disconnect from
* dead device.
*/
static void serio_raw_hangup(struct serio_raw *serio_raw)
{
struct serio_raw_client *client;
serio_pause_rx(serio_raw->serio);
list_for_each_entry(client, &serio_raw->client_list, node)
kill_fasync(&client->fasync, SIGIO, POLL_HUP);
serio_continue_rx(serio_raw->serio);
wake_up_interruptible(&serio_raw->wait);
}
static void serio_raw_disconnect(struct serio *serio)
{
struct serio_raw *serio_raw;
struct serio_raw *serio_raw = serio_get_drvdata(serio);
misc_deregister(&serio_raw->dev);
mutex_lock(&serio_raw_mutex);
serio_raw->dead = true;
list_del_init(&serio_raw->node);
mutex_unlock(&serio_raw_mutex);
serio_raw = serio_get_drvdata(serio);
serio_raw_hangup(serio_raw);
serio_close(serio);
kref_put(&serio_raw->kref, serio_raw_free);
serio_set_drvdata(serio, NULL);
serio_raw->serio = NULL;
if (!serio_raw_cleanup(serio_raw))
wake_up_interruptible(&serio_raw->wait);
mutex_unlock(&serio_raw_mutex);
}
static struct serio_device_id serio_raw_serio_ids[] = {
@ -391,7 +426,7 @@ static struct serio_driver serio_raw_drv = {
.connect = serio_raw_connect,
.reconnect = serio_raw_reconnect,
.disconnect = serio_raw_disconnect,
.manual_bind = 1,
.manual_bind = true,
};
static int __init serio_raw_init(void)

View file

@ -11,7 +11,7 @@
* Copyright (c) 2000 Daniel Egger <egger@suse.de>
* Copyright (c) 2001 Frederic Lepied <flepied@mandrakesoft.com>
* Copyright (c) 2004 Panagiotis Issaris <panagiotis.issaris@mech.kuleuven.ac.be>
* Copyright (c) 2002-2009 Ping Cheng <pingc@wacom.com>
* Copyright (c) 2002-2011 Ping Cheng <pingc@wacom.com>
*
* ChangeLog:
* v0.1 (vp) - Initial release
@ -93,7 +93,7 @@
/*
* Version Information
*/
#define DRIVER_VERSION "v1.52"
#define DRIVER_VERSION "v1.53"
#define DRIVER_AUTHOR "Vojtech Pavlik <vojtech@ucw.cz>"
#define DRIVER_DESC "USB Wacom tablet driver"
#define DRIVER_LICENSE "GPL"
@ -114,6 +114,12 @@ struct wacom {
struct mutex lock;
bool open;
char phys[32];
struct wacom_led {
u8 select[2]; /* status led selector (0..3) */
u8 llv; /* status led brightness no button (1..127) */
u8 hlv; /* status led brightness button pressed (1..127) */
u8 img_lum; /* OLED matrix display brightness */
} led;
};
extern const struct usb_device_id wacom_ids[];

View file

@ -48,27 +48,49 @@ struct hid_descriptor {
/* defines to get/set USB message */
#define USB_REQ_GET_REPORT 0x01
#define USB_REQ_SET_REPORT 0x09
#define WAC_HID_FEATURE_REPORT 0x03
#define WAC_MSG_RETRIES 5
static int usb_get_report(struct usb_interface *intf, unsigned char type,
unsigned char id, void *buf, int size)
#define WAC_CMD_LED_CONTROL 0x20
#define WAC_CMD_ICON_START 0x21
#define WAC_CMD_ICON_XFER 0x23
#define WAC_CMD_RETRIES 10
static int wacom_get_report(struct usb_interface *intf, u8 type, u8 id,
void *buf, size_t size, unsigned int retries)
{
return usb_control_msg(interface_to_usbdev(intf),
usb_rcvctrlpipe(interface_to_usbdev(intf), 0),
USB_REQ_GET_REPORT, USB_TYPE_CLASS | USB_RECIP_INTERFACE,
(type << 8) + id, intf->altsetting[0].desc.bInterfaceNumber,
buf, size, 100);
struct usb_device *dev = interface_to_usbdev(intf);
int retval;
do {
retval = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
USB_REQ_GET_REPORT,
USB_TYPE_CLASS | USB_RECIP_INTERFACE,
(type << 8) + id,
intf->altsetting[0].desc.bInterfaceNumber,
buf, size, 100);
} while ((retval == -ETIMEDOUT || retval == -EPIPE) && --retries);
return retval;
}
static int usb_set_report(struct usb_interface *intf, unsigned char type,
unsigned char id, void *buf, int size)
static int wacom_set_report(struct usb_interface *intf, u8 type, u8 id,
void *buf, size_t size, unsigned int retries)
{
return usb_control_msg(interface_to_usbdev(intf),
usb_sndctrlpipe(interface_to_usbdev(intf), 0),
USB_REQ_SET_REPORT, USB_TYPE_CLASS | USB_RECIP_INTERFACE,
(type << 8) + id, intf->altsetting[0].desc.bInterfaceNumber,
buf, size, 1000);
struct usb_device *dev = interface_to_usbdev(intf);
int retval;
do {
retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
USB_REQ_SET_REPORT,
USB_TYPE_CLASS | USB_RECIP_INTERFACE,
(type << 8) + id,
intf->altsetting[0].desc.bInterfaceNumber,
buf, size, 1000);
} while ((retval == -ETIMEDOUT || retval == -EPIPE) && --retries);
return retval;
}
static void wacom_sys_irq(struct urb *urb)
@ -319,23 +341,23 @@ static int wacom_query_tablet_data(struct usb_interface *intf, struct wacom_feat
rep_data[2] = 0;
rep_data[3] = 0;
report_id = 3;
error = usb_set_report(intf, WAC_HID_FEATURE_REPORT,
report_id, rep_data, 4);
error = wacom_set_report(intf, WAC_HID_FEATURE_REPORT,
report_id, rep_data, 4, 1);
if (error >= 0)
error = usb_get_report(intf,
WAC_HID_FEATURE_REPORT, report_id,
rep_data, 4);
error = wacom_get_report(intf,
WAC_HID_FEATURE_REPORT,
report_id, rep_data, 4, 1);
} while ((error < 0 || rep_data[1] != 4) && limit++ < WAC_MSG_RETRIES);
} else if (features->type != TABLETPC) {
do {
rep_data[0] = 2;
rep_data[1] = 2;
error = usb_set_report(intf, WAC_HID_FEATURE_REPORT,
report_id, rep_data, 2);
error = wacom_set_report(intf, WAC_HID_FEATURE_REPORT,
report_id, rep_data, 2, 1);
if (error >= 0)
error = usb_get_report(intf,
WAC_HID_FEATURE_REPORT, report_id,
rep_data, 2);
error = wacom_get_report(intf,
WAC_HID_FEATURE_REPORT,
report_id, rep_data, 2, 1);
} while ((error < 0 || rep_data[1] != 2) && limit++ < WAC_MSG_RETRIES);
}
@ -454,6 +476,275 @@ static void wacom_remove_shared_data(struct wacom_wac *wacom)
}
}
static int wacom_led_control(struct wacom *wacom)
{
unsigned char *buf;
int retval, led = 0;
buf = kzalloc(9, GFP_KERNEL);
if (!buf)
return -ENOMEM;
if (wacom->wacom_wac.features.type == WACOM_21UX2)
led = (wacom->led.select[1] << 4) | 0x40;
led |= wacom->led.select[0] | 0x4;
buf[0] = WAC_CMD_LED_CONTROL;
buf[1] = led;
buf[2] = wacom->led.llv;
buf[3] = wacom->led.hlv;
buf[4] = wacom->led.img_lum;
retval = wacom_set_report(wacom->intf, 0x03, WAC_CMD_LED_CONTROL,
buf, 9, WAC_CMD_RETRIES);
kfree(buf);
return retval;
}
static int wacom_led_putimage(struct wacom *wacom, int button_id, const void *img)
{
unsigned char *buf;
int i, retval;
buf = kzalloc(259, GFP_KERNEL);
if (!buf)
return -ENOMEM;
/* Send 'start' command */
buf[0] = WAC_CMD_ICON_START;
buf[1] = 1;
retval = wacom_set_report(wacom->intf, 0x03, WAC_CMD_ICON_START,
buf, 2, WAC_CMD_RETRIES);
if (retval < 0)
goto out;
buf[0] = WAC_CMD_ICON_XFER;
buf[1] = button_id & 0x07;
for (i = 0; i < 4; i++) {
buf[2] = i;
memcpy(buf + 3, img + i * 256, 256);
retval = wacom_set_report(wacom->intf, 0x03, WAC_CMD_ICON_XFER,
buf, 259, WAC_CMD_RETRIES);
if (retval < 0)
break;
}
/* Send 'stop' */
buf[0] = WAC_CMD_ICON_START;
buf[1] = 0;
wacom_set_report(wacom->intf, 0x03, WAC_CMD_ICON_START,
buf, 2, WAC_CMD_RETRIES);
out:
kfree(buf);
return retval;
}
static ssize_t wacom_led_select_store(struct device *dev, int set_id,
const char *buf, size_t count)
{
struct wacom *wacom = dev_get_drvdata(dev);
unsigned int id;
int err;
err = kstrtouint(buf, 10, &id);
if (err)
return err;
mutex_lock(&wacom->lock);
wacom->led.select[set_id] = id & 0x3;
err = wacom_led_control(wacom);
mutex_unlock(&wacom->lock);
return err < 0 ? err : count;
}
#define DEVICE_LED_SELECT_ATTR(SET_ID) \
static ssize_t wacom_led##SET_ID##_select_store(struct device *dev, \
struct device_attribute *attr, const char *buf, size_t count) \
{ \
return wacom_led_select_store(dev, SET_ID, buf, count); \
} \
static ssize_t wacom_led##SET_ID##_select_show(struct device *dev, \
struct device_attribute *attr, char *buf) \
{ \
struct wacom *wacom = dev_get_drvdata(dev); \
return snprintf(buf, 2, "%d\n", wacom->led.select[SET_ID]); \
} \
static DEVICE_ATTR(status_led##SET_ID##_select, S_IWUSR | S_IRUSR, \
wacom_led##SET_ID##_select_show, \
wacom_led##SET_ID##_select_store)
DEVICE_LED_SELECT_ATTR(0);
DEVICE_LED_SELECT_ATTR(1);
static ssize_t wacom_luminance_store(struct wacom *wacom, u8 *dest,
const char *buf, size_t count)
{
unsigned int value;
int err;
err = kstrtouint(buf, 10, &value);
if (err)
return err;
mutex_lock(&wacom->lock);
*dest = value & 0x7f;
err = wacom_led_control(wacom);
mutex_unlock(&wacom->lock);
return err < 0 ? err : count;
}
#define DEVICE_LUMINANCE_ATTR(name, field) \
static ssize_t wacom_##name##_luminance_store(struct device *dev, \
struct device_attribute *attr, const char *buf, size_t count) \
{ \
struct wacom *wacom = dev_get_drvdata(dev); \
\
return wacom_luminance_store(wacom, &wacom->led.field, \
buf, count); \
} \
static DEVICE_ATTR(name##_luminance, S_IWUSR, \
NULL, wacom_##name##_luminance_store)
DEVICE_LUMINANCE_ATTR(status0, llv);
DEVICE_LUMINANCE_ATTR(status1, hlv);
DEVICE_LUMINANCE_ATTR(buttons, img_lum);
static ssize_t wacom_button_image_store(struct device *dev, int button_id,
const char *buf, size_t count)
{
struct wacom *wacom = dev_get_drvdata(dev);
int err;
if (count != 1024)
return -EINVAL;
mutex_lock(&wacom->lock);
err = wacom_led_putimage(wacom, button_id, buf);
mutex_unlock(&wacom->lock);
return err < 0 ? err : count;
}
#define DEVICE_BTNIMG_ATTR(BUTTON_ID) \
static ssize_t wacom_btnimg##BUTTON_ID##_store(struct device *dev, \
struct device_attribute *attr, const char *buf, size_t count) \
{ \
return wacom_button_image_store(dev, BUTTON_ID, buf, count); \
} \
static DEVICE_ATTR(button##BUTTON_ID##_rawimg, S_IWUSR, \
NULL, wacom_btnimg##BUTTON_ID##_store)
DEVICE_BTNIMG_ATTR(0);
DEVICE_BTNIMG_ATTR(1);
DEVICE_BTNIMG_ATTR(2);
DEVICE_BTNIMG_ATTR(3);
DEVICE_BTNIMG_ATTR(4);
DEVICE_BTNIMG_ATTR(5);
DEVICE_BTNIMG_ATTR(6);
DEVICE_BTNIMG_ATTR(7);
static struct attribute *cintiq_led_attrs[] = {
&dev_attr_status_led0_select.attr,
&dev_attr_status_led1_select.attr,
NULL
};
static struct attribute_group cintiq_led_attr_group = {
.name = "wacom_led",
.attrs = cintiq_led_attrs,
};
static struct attribute *intuos4_led_attrs[] = {
&dev_attr_status0_luminance.attr,
&dev_attr_status1_luminance.attr,
&dev_attr_status_led0_select.attr,
&dev_attr_buttons_luminance.attr,
&dev_attr_button0_rawimg.attr,
&dev_attr_button1_rawimg.attr,
&dev_attr_button2_rawimg.attr,
&dev_attr_button3_rawimg.attr,
&dev_attr_button4_rawimg.attr,
&dev_attr_button5_rawimg.attr,
&dev_attr_button6_rawimg.attr,
&dev_attr_button7_rawimg.attr,
NULL
};
static struct attribute_group intuos4_led_attr_group = {
.name = "wacom_led",
.attrs = intuos4_led_attrs,
};
static int wacom_initialize_leds(struct wacom *wacom)
{
int error;
/* Initialize default values */
switch (wacom->wacom_wac.features.type) {
case INTUOS4:
case INTUOS4L:
wacom->led.select[0] = 0;
wacom->led.select[1] = 0;
wacom->led.llv = 10;
wacom->led.hlv = 20;
wacom->led.img_lum = 10;
error = sysfs_create_group(&wacom->intf->dev.kobj,
&intuos4_led_attr_group);
break;
case WACOM_21UX2:
wacom->led.select[0] = 0;
wacom->led.select[1] = 0;
wacom->led.llv = 0;
wacom->led.hlv = 0;
wacom->led.img_lum = 0;
error = sysfs_create_group(&wacom->intf->dev.kobj,
&cintiq_led_attr_group);
break;
default:
return 0;
}
if (error) {
dev_err(&wacom->intf->dev,
"cannot create sysfs group err: %d\n", error);
return error;
}
wacom_led_control(wacom);
return 0;
}
static void wacom_destroy_leds(struct wacom *wacom)
{
switch (wacom->wacom_wac.features.type) {
case INTUOS4:
case INTUOS4L:
sysfs_remove_group(&wacom->intf->dev.kobj,
&intuos4_led_attr_group);
break;
case WACOM_21UX2:
sysfs_remove_group(&wacom->intf->dev.kobj,
&cintiq_led_attr_group);
break;
}
}
static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
struct usb_device *dev = interface_to_usbdev(intf);
@ -542,16 +833,21 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
wacom->irq->transfer_dma = wacom->data_dma;
wacom->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
error = input_register_device(input_dev);
error = wacom_initialize_leds(wacom);
if (error)
goto fail4;
error = input_register_device(input_dev);
if (error)
goto fail5;
/* Note that if query fails it is not a hard failure */
wacom_query_tablet_data(intf, features);
usb_set_intfdata(intf, wacom);
return 0;
fail5: wacom_destroy_leds(wacom);
fail4: wacom_remove_shared_data(wacom_wac);
fail3: usb_free_urb(wacom->irq);
fail2: usb_free_coherent(dev, WACOM_PKGLEN_MAX, wacom_wac->data, wacom->data_dma);
@ -568,6 +864,7 @@ static void wacom_disconnect(struct usb_interface *intf)
usb_kill_urb(wacom->irq);
input_unregister_device(wacom->wacom_wac.input);
wacom_destroy_leds(wacom);
usb_free_urb(wacom->irq);
usb_free_coherent(interface_to_usbdev(intf), WACOM_PKGLEN_MAX,
wacom->wacom_wac.data, wacom->data_dma);
@ -590,17 +887,16 @@ static int wacom_resume(struct usb_interface *intf)
{
struct wacom *wacom = usb_get_intfdata(intf);
struct wacom_features *features = &wacom->wacom_wac.features;
int rv;
int rv = 0;
mutex_lock(&wacom->lock);
/* switch to wacom mode first */
wacom_query_tablet_data(intf, features);
wacom_led_control(wacom);
if (wacom->open)
rv = usb_submit_urb(wacom->irq, GFP_NOIO);
else
rv = 0;
if (wacom->open && usb_submit_urb(wacom->irq, GFP_NOIO) < 0)
rv = -EIO;
mutex_unlock(&wacom->lock);

View file

@ -874,7 +874,15 @@ static int wacom_bpt_pen(struct wacom_wac *wacom)
x = le16_to_cpup((__le16 *)&data[2]);
y = le16_to_cpup((__le16 *)&data[4]);
p = le16_to_cpup((__le16 *)&data[6]);
d = data[8];
/*
* Convert distance from out prox to distance from tablet.
* distance will be greater than distance_max once
* touching and applying pressure; do not report negative
* distance.
*/
if (data[8] <= wacom->features.distance_max)
d = wacom->features.distance_max - data[8];
pen = data[1] & 0x01;
btn1 = data[1] & 0x02;
btn2 = data[1] & 0x04;
@ -1030,8 +1038,6 @@ void wacom_setup_device_quirks(struct wacom_features *features)
features->y_max <<= 5;
features->x_fuzz <<= 5;
features->y_fuzz <<= 5;
features->pressure_max = 256;
features->pressure_fuzz = 16;
features->quirks |= WACOM_QUIRK_BBTOUCH_LOWRES;
}
}
@ -1241,14 +1247,14 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev,
input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
0, features->y_max,
features->y_fuzz, 0);
input_set_abs_params(input_dev, ABS_MT_PRESSURE,
0, features->pressure_max,
features->pressure_fuzz, 0);
} else if (features->device_type == BTN_TOOL_PEN) {
__set_bit(BTN_TOOL_RUBBER, input_dev->keybit);
__set_bit(BTN_TOOL_PEN, input_dev->keybit);
__set_bit(BTN_STYLUS, input_dev->keybit);
__set_bit(BTN_STYLUS2, input_dev->keybit);
input_set_abs_params(input_dev, ABS_DISTANCE, 0,
features->distance_max,
0, 0);
}
break;
}
@ -1469,37 +1475,37 @@ static const struct wacom_features wacom_features_0x47 =
31, INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
static const struct wacom_features wacom_features_0xD0 =
{ "Wacom Bamboo 2FG", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023,
63, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
static const struct wacom_features wacom_features_0xD1 =
{ "Wacom Bamboo 2FG 4x5", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023,
63, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
static const struct wacom_features wacom_features_0xD2 =
{ "Wacom Bamboo Craft", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023,
63, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
static const struct wacom_features wacom_features_0xD3 =
{ "Wacom Bamboo 2FG 6x8", WACOM_PKGLEN_BBFUN, 21648, 13530, 1023,
63, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
{ "Wacom Bamboo 2FG 6x8", WACOM_PKGLEN_BBFUN, 21648, 13700, 1023,
31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
static const struct wacom_features wacom_features_0xD4 =
{ "Wacom Bamboo Pen", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023,
63, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
static const struct wacom_features wacom_features_0xD5 =
{ "Wacom Bamboo Pen 6x8", WACOM_PKGLEN_BBFUN, 21648, 13530, 1023,
63, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
{ "Wacom Bamboo Pen 6x8", WACOM_PKGLEN_BBFUN, 21648, 13700, 1023,
31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
static const struct wacom_features wacom_features_0xD6 =
{ "Wacom BambooPT 2FG 4x5", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023,
63, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
static const struct wacom_features wacom_features_0xD7 =
{ "Wacom BambooPT 2FG Small", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023,
63, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
static const struct wacom_features wacom_features_0xD8 =
{ "Wacom Bamboo Comic 2FG", WACOM_PKGLEN_BBFUN, 21648, 13530, 1023,
63, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
{ "Wacom Bamboo Comic 2FG", WACOM_PKGLEN_BBFUN, 21648, 13700, 1023,
31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
static const struct wacom_features wacom_features_0xDA =
{ "Wacom Bamboo 2FG 4x5 SE", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023,
63, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
static struct wacom_features wacom_features_0xDB =
{ "Wacom Bamboo 2FG 6x8 SE", WACOM_PKGLEN_BBFUN, 21648, 13530, 1023,
63, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
{ "Wacom Bamboo 2FG 6x8 SE", WACOM_PKGLEN_BBFUN, 21648, 13700, 1023,
31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
static const struct wacom_features wacom_features_0x6004 =
{ "ISD-V4", WACOM_PKGLEN_GRAPHIRE, 12800, 8000, 255,
0, TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };

View file

@ -651,6 +651,18 @@ config TOUCHSCREEN_TOUCHIT213
To compile this driver as a module, choose M here: the
module will be called touchit213.
config TOUCHSCREEN_TSC_SERIO
tristate "TSC-10/25/40 serial touchscreen support"
select SERIO
help
Say Y here if you have a TSC-10, 25 or 40 serial touchscreen connected
to your system.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called tsc40.
config TOUCHSCREEN_TSC2005
tristate "TSC2005 based touchscreens"
depends on SPI_MASTER && GENERIC_HARDIRQS

View file

@ -46,6 +46,7 @@ obj-$(CONFIG_TOUCHSCREEN_TNETV107X) += tnetv107x-ts.o
obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213) += touchit213.o
obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT) += touchright.o
obj-$(CONFIG_TOUCHSCREEN_TOUCHWIN) += touchwin.o
obj-$(CONFIG_TOUCHSCREEN_TSC_SERIO) += tsc40.o
obj-$(CONFIG_TOUCHSCREEN_TSC2005) += tsc2005.o
obj-$(CONFIG_TOUCHSCREEN_TSC2007) += tsc2007.o
obj-$(CONFIG_TOUCHSCREEN_UCB1400) += ucb1400_ts.o

View file

@ -16,7 +16,7 @@
#define AD7879_DEVID 0x79 /* AD7879-1/AD7889-1 */
#ifdef CONFIG_PM
#ifdef CONFIG_PM_SLEEP
static int ad7879_i2c_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
@ -36,9 +36,9 @@ static int ad7879_i2c_resume(struct device *dev)
return 0;
}
#endif
static SIMPLE_DEV_PM_OPS(ad7879_i2c_pm, ad7879_i2c_suspend, ad7879_i2c_resume);
#endif
/* All registers are word-sized.
* AD7879 uses a high-byte first convention.
@ -119,9 +119,7 @@ static struct i2c_driver ad7879_i2c_driver = {
.driver = {
.name = "ad7879",
.owner = THIS_MODULE,
#ifdef CONFIG_PM
.pm = &ad7879_i2c_pm,
#endif
},
.probe = ad7879_i2c_probe,
.remove = __devexit_p(ad7879_i2c_remove),

View file

@ -910,12 +910,17 @@ static ssize_t mxt_object_show(struct device *dev,
for (i = 0; i < data->info.object_num; i++) {
object = data->object_table + i;
count += sprintf(buf + count,
"Object Table Element %d(Type %d)\n",
count += snprintf(buf + count, PAGE_SIZE - count,
"Object[%d] (Type %d)\n",
i + 1, object->type);
if (count >= PAGE_SIZE)
return PAGE_SIZE - 1;
if (!mxt_object_readable(object->type)) {
count += sprintf(buf + count, "\n");
count += snprintf(buf + count, PAGE_SIZE - count,
"\n");
if (count >= PAGE_SIZE)
return PAGE_SIZE - 1;
continue;
}
@ -925,11 +930,15 @@ static ssize_t mxt_object_show(struct device *dev,
if (error)
return error;
count += sprintf(buf + count,
" Byte %d: 0x%x (%d)\n", j, val, val);
count += snprintf(buf + count, PAGE_SIZE - count,
"\t[%2d]: %02x (%d)\n", j, val, val);
if (count >= PAGE_SIZE)
return PAGE_SIZE - 1;
}
count += sprintf(buf + count, "\n");
count += snprintf(buf + count, PAGE_SIZE - count, "\n");
if (count >= PAGE_SIZE)
return PAGE_SIZE - 1;
}
return count;

View file

@ -229,7 +229,7 @@ static int __devinit atmel_tsadcc_probe(struct platform_device *pdev)
goto err_release_mem;
}
err = request_irq(ts_dev->irq, atmel_tsadcc_interrupt, IRQF_DISABLED,
err = request_irq(ts_dev->irq, atmel_tsadcc_interrupt, 0,
pdev->dev.driver->name, ts_dev);
if (err) {
dev_err(&pdev->dev, "failed to allocate irq.\n");

View file

@ -396,14 +396,14 @@ static int h3600ts_connect(struct serio *serio, struct serio_driver *drv)
set_GPIO_IRQ_edge(GPIO_BITSY_NPOWER_BUTTON, GPIO_RISING_EDGE);
if (request_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, action_button_handler,
IRQF_SHARED | IRQF_DISABLED, "h3600_action", ts->dev)) {
IRQF_SHARED, "h3600_action", ts->dev)) {
printk(KERN_ERR "h3600ts.c: Could not allocate Action Button IRQ!\n");
err = -EBUSY;
goto fail1;
}
if (request_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, npower_button_handler,
IRQF_SHARED | IRQF_DISABLED, "h3600_suspend", ts->dev)) {
IRQF_SHARED, "h3600_suspend", ts->dev)) {
printk(KERN_ERR "h3600ts.c: Could not allocate Power Button IRQ!\n");
err = -EBUSY;
goto fail2;

View file

@ -93,7 +93,7 @@ static int __init hp680_ts_init(void)
hp680_ts_dev->phys = "hp680_ts/input0";
if (request_irq(HP680_TS_IRQ, hp680_ts_interrupt,
IRQF_DISABLED, MODNAME, 0) < 0) {
0, MODNAME, 0) < 0) {
printk(KERN_ERR "hp680_touchscreen.c: Can't allocate irq %d\n",
HP680_TS_IRQ);
err = -EBUSY;

View file

@ -127,7 +127,7 @@ static int __devinit jornada720_ts_probe(struct platform_device *pdev)
error = request_irq(IRQ_GPIO9,
jornada720_ts_interrupt,
IRQF_DISABLED | IRQF_TRIGGER_RISING,
IRQF_TRIGGER_RISING,
"HP7XX Touchscreen driver", pdev);
if (error) {
printk(KERN_INFO "HP7XX TS : Unable to acquire irq!\n");

View file

@ -276,7 +276,7 @@ static int __devinit lpc32xx_ts_probe(struct platform_device *pdev)
input_set_drvdata(input, tsc);
error = request_irq(tsc->irq, lpc32xx_ts_interrupt,
IRQF_DISABLED, pdev->name, tsc);
0, pdev->name, tsc);
if (error) {
dev_err(&pdev->dev, "failed requesting interrupt\n");
goto err_put_clock;

View file

@ -2,6 +2,7 @@
* Penmount serial touchscreen driver
*
* Copyright (c) 2006 Rick Koch <n1gp@hotmail.com>
* Copyright (c) 2011 John Sung <penmount.touch@gmail.com>
*
* Based on ELO driver (drivers/input/touchscreen/elo.c)
* Copyright (c) 2004 Vojtech Pavlik
@ -18,12 +19,14 @@
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/input/mt.h>
#include <linux/serio.h>
#include <linux/init.h>
#define DRIVER_DESC "Penmount serial touchscreen driver"
#define DRIVER_DESC "PenMount serial touchscreen driver"
MODULE_AUTHOR("Rick Koch <n1gp@hotmail.com>");
MODULE_AUTHOR("John Sung <penmount.touch@gmail.com>");
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
@ -31,7 +34,19 @@ MODULE_LICENSE("GPL");
* Definitions & global arrays.
*/
#define PM_MAX_LENGTH 5
#define PM_MAX_LENGTH 6
#define PM_MAX_MTSLOT 16
#define PM_3000_MTSLOT 2
#define PM_6250_MTSLOT 12
/*
* Multi-touch slot
*/
struct mt_slot {
unsigned short x, y;
bool active; /* is the touch valid? */
};
/*
* Per-touchscreen data.
@ -43,25 +58,119 @@ struct pm {
int idx;
unsigned char data[PM_MAX_LENGTH];
char phys[32];
unsigned char packetsize;
unsigned char maxcontacts;
struct mt_slot slots[PM_MAX_MTSLOT];
void (*parse_packet)(struct pm *);
};
/*
* pm_mtevent() sends mt events and also emulates pointer movement
*/
static void pm_mtevent(struct pm *pm, struct input_dev *input)
{
int i;
for (i = 0; i < pm->maxcontacts; ++i) {
input_mt_slot(input, i);
input_mt_report_slot_state(input, MT_TOOL_FINGER,
pm->slots[i].active);
if (pm->slots[i].active) {
input_event(input, EV_ABS, ABS_MT_POSITION_X, pm->slots[i].x);
input_event(input, EV_ABS, ABS_MT_POSITION_Y, pm->slots[i].y);
}
}
input_mt_report_pointer_emulation(input, true);
input_sync(input);
}
/*
* pm_checkpacket() checks if data packet is valid
*/
static bool pm_checkpacket(unsigned char *packet)
{
int total = 0;
int i;
for (i = 0; i < 5; i++)
total += packet[i];
return packet[5] == (unsigned char)~(total & 0xff);
}
static void pm_parse_9000(struct pm *pm)
{
struct input_dev *dev = pm->dev;
if ((pm->data[0] & 0x80) && pm->packetsize == ++pm->idx) {
input_report_abs(dev, ABS_X, pm->data[1] * 128 + pm->data[2]);
input_report_abs(dev, ABS_Y, pm->data[3] * 128 + pm->data[4]);
input_report_key(dev, BTN_TOUCH, !!(pm->data[0] & 0x40));
input_sync(dev);
pm->idx = 0;
}
}
static void pm_parse_6000(struct pm *pm)
{
struct input_dev *dev = pm->dev;
if ((pm->data[0] & 0xbf) == 0x30 && pm->packetsize == ++pm->idx) {
if (pm_checkpacket(pm->data)) {
input_report_abs(dev, ABS_X,
pm->data[2] * 256 + pm->data[1]);
input_report_abs(dev, ABS_Y,
pm->data[4] * 256 + pm->data[3]);
input_report_key(dev, BTN_TOUCH, pm->data[0] & 0x40);
input_sync(dev);
}
pm->idx = 0;
}
}
static void pm_parse_3000(struct pm *pm)
{
struct input_dev *dev = pm->dev;
if ((pm->data[0] & 0xce) == 0x40 && pm->packetsize == ++pm->idx) {
if (pm_checkpacket(pm->data)) {
int slotnum = pm->data[0] & 0x0f;
pm->slots[slotnum].active = pm->data[0] & 0x30;
pm->slots[slotnum].x = pm->data[2] * 256 + pm->data[1];
pm->slots[slotnum].y = pm->data[4] * 256 + pm->data[3];
pm_mtevent(pm, dev);
}
pm->idx = 0;
}
}
static void pm_parse_6250(struct pm *pm)
{
struct input_dev *dev = pm->dev;
if ((pm->data[0] & 0xb0) == 0x30 && pm->packetsize == ++pm->idx) {
if (pm_checkpacket(pm->data)) {
int slotnum = pm->data[0] & 0x0f;
pm->slots[slotnum].active = pm->data[0] & 0x40;
pm->slots[slotnum].x = pm->data[2] * 256 + pm->data[1];
pm->slots[slotnum].y = pm->data[4] * 256 + pm->data[3];
pm_mtevent(pm, dev);
}
pm->idx = 0;
}
}
static irqreturn_t pm_interrupt(struct serio *serio,
unsigned char data, unsigned int flags)
{
struct pm *pm = serio_get_drvdata(serio);
struct input_dev *dev = pm->dev;
pm->data[pm->idx] = data;
if (pm->data[0] & 0x80) {
if (PM_MAX_LENGTH == ++pm->idx) {
input_report_abs(dev, ABS_X, pm->data[2] * 128 + pm->data[1]);
input_report_abs(dev, ABS_Y, pm->data[4] * 128 + pm->data[3]);
input_report_key(dev, BTN_TOUCH, !!(pm->data[0] & 0x40));
input_sync(dev);
pm->idx = 0;
}
}
pm->parse_packet(pm);
return IRQ_HANDLED;
}
@ -74,17 +183,17 @@ static void pm_disconnect(struct serio *serio)
{
struct pm *pm = serio_get_drvdata(serio);
input_get_device(pm->dev);
input_unregister_device(pm->dev);
serio_close(serio);
serio_set_drvdata(serio, NULL);
input_put_device(pm->dev);
input_unregister_device(pm->dev);
kfree(pm);
serio_set_drvdata(serio, NULL);
}
/*
* pm_connect() is the routine that is called when someone adds a
* new serio device that supports Gunze protocol and registers it as
* new serio device that supports PenMount protocol and registers it as
* an input device.
*/
@ -92,6 +201,7 @@ static int pm_connect(struct serio *serio, struct serio_driver *drv)
{
struct pm *pm;
struct input_dev *input_dev;
int max_x, max_y;
int err;
pm = kzalloc(sizeof(struct pm), GFP_KERNEL);
@ -104,8 +214,9 @@ static int pm_connect(struct serio *serio, struct serio_driver *drv)
pm->serio = serio;
pm->dev = input_dev;
snprintf(pm->phys, sizeof(pm->phys), "%s/input0", serio->phys);
pm->maxcontacts = 1;
input_dev->name = "Penmount Serial TouchScreen";
input_dev->name = "PenMount Serial TouchScreen";
input_dev->phys = pm->phys;
input_dev->id.bustype = BUS_RS232;
input_dev->id.vendor = SERIO_PENMOUNT;
@ -113,10 +224,52 @@ static int pm_connect(struct serio *serio, struct serio_driver *drv)
input_dev->id.version = 0x0100;
input_dev->dev.parent = &serio->dev;
input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
input_set_abs_params(pm->dev, ABS_X, 0, 0x3ff, 0, 0);
input_set_abs_params(pm->dev, ABS_Y, 0, 0x3ff, 0, 0);
input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
switch (serio->id.id) {
default:
case 0:
pm->packetsize = 5;
pm->parse_packet = pm_parse_9000;
input_dev->id.product = 0x9000;
max_x = max_y = 0x3ff;
break;
case 1:
pm->packetsize = 6;
pm->parse_packet = pm_parse_6000;
input_dev->id.product = 0x6000;
max_x = max_y = 0x3ff;
break;
case 2:
pm->packetsize = 6;
pm->parse_packet = pm_parse_3000;
input_dev->id.product = 0x3000;
max_x = max_y = 0x7ff;
pm->maxcontacts = PM_3000_MTSLOT;
break;
case 3:
pm->packetsize = 6;
pm->parse_packet = pm_parse_6250;
input_dev->id.product = 0x6250;
max_x = max_y = 0x3ff;
pm->maxcontacts = PM_6250_MTSLOT;
break;
}
input_set_abs_params(pm->dev, ABS_X, 0, max_x, 0, 0);
input_set_abs_params(pm->dev, ABS_Y, 0, max_y, 0, 0);
if (pm->maxcontacts > 1) {
input_mt_init_slots(pm->dev, pm->maxcontacts);
input_set_abs_params(pm->dev,
ABS_MT_POSITION_X, 0, max_x, 0, 0);
input_set_abs_params(pm->dev,
ABS_MT_POSITION_Y, 0, max_y, 0, 0);
}
serio_set_drvdata(serio, pm);
@ -155,7 +308,7 @@ MODULE_DEVICE_TABLE(serio, pm_serio_ids);
static struct serio_driver pm_drv = {
.driver = {
.name = "penmountlpc",
.name = "serio-penmount",
},
.description = DRIVER_DESC,
.id_table = pm_serio_ids,

View file

@ -328,7 +328,7 @@ static int __devinit s3c2410ts_probe(struct platform_device *pdev)
ts.shift = info->oversampling_shift;
ts.features = platform_get_device_id(pdev)->driver_data;
ret = request_irq(ts.irq_tc, stylus_irq, IRQF_DISABLED,
ret = request_irq(ts.irq_tc, stylus_irq, 0,
"s3c2410_ts_pen", ts.input);
if (ret) {
dev_err(dev, "cannot get TC interrupt\n");

View file

@ -66,7 +66,6 @@ struct ts_event {
struct tsc2007 {
struct input_dev *input;
char phys[32];
struct delayed_work work;
struct i2c_client *client;
@ -76,9 +75,11 @@ struct tsc2007 {
unsigned long poll_delay;
unsigned long poll_period;
bool pendown;
int irq;
wait_queue_head_t wait;
bool stopped;
int (*get_pendown_state)(void);
void (*clear_penirq)(void);
};
@ -141,25 +142,8 @@ static u32 tsc2007_calculate_pressure(struct tsc2007 *tsc, struct ts_event *tc)
return rt;
}
static void tsc2007_send_up_event(struct tsc2007 *tsc)
static bool tsc2007_is_pen_down(struct tsc2007 *ts)
{
struct input_dev *input = tsc->input;
dev_dbg(&tsc->client->dev, "UP\n");
input_report_key(input, BTN_TOUCH, 0);
input_report_abs(input, ABS_PRESSURE, 0);
input_sync(input);
}
static void tsc2007_work(struct work_struct *work)
{
struct tsc2007 *ts =
container_of(to_delayed_work(work), struct tsc2007, work);
bool debounced = false;
struct ts_event tc;
u32 rt;
/*
* NOTE: We can't rely on the pressure to determine the pen down
* state, even though this controller has a pressure sensor.
@ -170,97 +154,123 @@ static void tsc2007_work(struct work_struct *work)
* The only safe way to check for the pen up condition is in the
* work function by reading the pen signal state (it's a GPIO
* and IRQ). Unfortunately such callback is not always available,
* in that case we have rely on the pressure anyway.
* in that case we assume that the pen is down and expect caller
* to fall back on the pressure reading.
*/
if (ts->get_pendown_state) {
if (unlikely(!ts->get_pendown_state())) {
tsc2007_send_up_event(ts);
ts->pendown = false;
goto out;
}
dev_dbg(&ts->client->dev, "pen is still down\n");
}
if (!ts->get_pendown_state)
return true;
tsc2007_read_values(ts, &tc);
rt = tsc2007_calculate_pressure(ts, &tc);
if (rt > ts->max_rt) {
/*
* 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.
*/
dev_dbg(&ts->client->dev, "ignored pressure %d\n", rt);
debounced = true;
goto out;
}
if (rt) {
struct input_dev *input = ts->input;
if (!ts->pendown) {
dev_dbg(&ts->client->dev, "DOWN\n");
input_report_key(input, BTN_TOUCH, 1);
ts->pendown = true;
}
input_report_abs(input, ABS_X, tc.x);
input_report_abs(input, ABS_Y, tc.y);
input_report_abs(input, ABS_PRESSURE, rt);
input_sync(input);
dev_dbg(&ts->client->dev, "point(%4d,%4d), pressure (%4u)\n",
tc.x, tc.y, rt);
} else if (!ts->get_pendown_state && ts->pendown) {
/*
* We don't have callback to check pendown state, so we
* have to assume that since pressure reported is 0 the
* pen was lifted up.
*/
tsc2007_send_up_event(ts);
ts->pendown = false;
}
out:
if (ts->pendown || debounced)
schedule_delayed_work(&ts->work,
msecs_to_jiffies(ts->poll_period));
else
enable_irq(ts->irq);
return ts->get_pendown_state();
}
static irqreturn_t tsc2007_irq(int irq, void *handle)
static irqreturn_t tsc2007_soft_irq(int irq, void *handle)
{
struct tsc2007 *ts = handle;
struct input_dev *input = ts->input;
struct ts_event tc;
u32 rt;
if (!ts->get_pendown_state || likely(ts->get_pendown_state())) {
disable_irq_nosync(ts->irq);
schedule_delayed_work(&ts->work,
msecs_to_jiffies(ts->poll_delay));
while (!ts->stopped && tsc2007_is_pen_down(ts)) {
/* pen is down, continue with the measurement */
tsc2007_read_values(ts, &tc);
rt = tsc2007_calculate_pressure(ts, &tc);
if (rt == 0 && !ts->get_pendown_state) {
/*
* If pressure reported is 0 and we don't have
* callback to check pendown state, we have to
* assume that pen was lifted up.
*/
break;
}
if (rt <= ts->max_rt) {
dev_dbg(&ts->client->dev,
"DOWN point(%4d,%4d), pressure (%4u)\n",
tc.x, tc.y, rt);
input_report_key(input, BTN_TOUCH, 1);
input_report_abs(input, ABS_X, tc.x);
input_report_abs(input, ABS_Y, tc.y);
input_report_abs(input, ABS_PRESSURE, rt);
input_sync(input);
} else {
/*
* 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.
*/
dev_dbg(&ts->client->dev, "ignored pressure %d\n", rt);
}
wait_event_timeout(ts->wait, ts->stopped,
msecs_to_jiffies(ts->poll_period));
}
dev_dbg(&ts->client->dev, "UP\n");
input_report_key(input, BTN_TOUCH, 0);
input_report_abs(input, ABS_PRESSURE, 0);
input_sync(input);
if (ts->clear_penirq)
ts->clear_penirq();
return IRQ_HANDLED;
}
static void tsc2007_free_irq(struct tsc2007 *ts)
static irqreturn_t tsc2007_hard_irq(int irq, void *handle)
{
free_irq(ts->irq, ts);
if (cancel_delayed_work_sync(&ts->work)) {
/*
* Work was pending, therefore we need to enable
* IRQ here to balance the disable_irq() done in the
* interrupt handler.
*/
enable_irq(ts->irq);
struct tsc2007 *ts = handle;
if (!ts->get_pendown_state || likely(ts->get_pendown_state()))
return IRQ_WAKE_THREAD;
if (ts->clear_penirq)
ts->clear_penirq();
return IRQ_HANDLED;
}
static void tsc2007_stop(struct tsc2007 *ts)
{
ts->stopped = true;
mb();
wake_up(&ts->wait);
disable_irq(ts->irq);
}
static int tsc2007_open(struct input_dev *input_dev)
{
struct tsc2007 *ts = input_get_drvdata(input_dev);
int err;
ts->stopped = false;
mb();
enable_irq(ts->irq);
/* Prepare for touch readings - power down ADC and enable PENIRQ */
err = tsc2007_xfer(ts, PWRDOWN);
if (err < 0) {
tsc2007_stop(ts);
return err;
}
return 0;
}
static void tsc2007_close(struct input_dev *input_dev)
{
struct tsc2007 *ts = input_get_drvdata(input_dev);
tsc2007_stop(ts);
}
static int __devinit tsc2007_probe(struct i2c_client *client,
@ -290,7 +300,7 @@ static int __devinit tsc2007_probe(struct i2c_client *client,
ts->client = client;
ts->irq = client->irq;
ts->input = input_dev;
INIT_DELAYED_WORK(&ts->work, tsc2007_work);
init_waitqueue_head(&ts->wait);
ts->model = pdata->model;
ts->x_plate_ohms = pdata->x_plate_ohms;
@ -300,6 +310,12 @@ static int __devinit tsc2007_probe(struct i2c_client *client,
ts->get_pendown_state = pdata->get_pendown_state;
ts->clear_penirq = pdata->clear_penirq;
if (pdata->x_plate_ohms == 0) {
dev_err(&client->dev, "x_plate_ohms is not set up in platform data");
err = -EINVAL;
goto err_free_mem;
}
snprintf(ts->phys, sizeof(ts->phys),
"%s/input0", dev_name(&client->dev));
@ -307,6 +323,11 @@ static int __devinit tsc2007_probe(struct i2c_client *client,
input_dev->phys = ts->phys;
input_dev->id.bustype = BUS_I2C;
input_dev->open = tsc2007_open;
input_dev->close = tsc2007_close;
input_set_drvdata(input_dev, ts);
input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
@ -318,17 +339,14 @@ static int __devinit tsc2007_probe(struct i2c_client *client,
if (pdata->init_platform_hw)
pdata->init_platform_hw();
err = request_irq(ts->irq, tsc2007_irq, 0,
client->dev.driver->name, ts);
err = request_threaded_irq(ts->irq, tsc2007_hard_irq, tsc2007_soft_irq,
IRQF_ONESHOT, client->dev.driver->name, ts);
if (err < 0) {
dev_err(&client->dev, "irq %d busy?\n", ts->irq);
goto err_free_mem;
}
/* Prepare for touch readings - power down ADC and enable PENIRQ */
err = tsc2007_xfer(ts, PWRDOWN);
if (err < 0)
goto err_free_irq;
tsc2007_stop(ts);
err = input_register_device(input_dev);
if (err)
@ -339,7 +357,7 @@ static int __devinit tsc2007_probe(struct i2c_client *client,
return 0;
err_free_irq:
tsc2007_free_irq(ts);
free_irq(ts->irq, ts);
if (pdata->exit_platform_hw)
pdata->exit_platform_hw();
err_free_mem:
@ -353,7 +371,7 @@ static int __devexit tsc2007_remove(struct i2c_client *client)
struct tsc2007 *ts = i2c_get_clientdata(client);
struct tsc2007_platform_data *pdata = client->dev.platform_data;
tsc2007_free_irq(ts);
free_irq(ts->irq, ts);
if (pdata->exit_platform_hw)
pdata->exit_platform_hw();

View file

@ -0,0 +1,184 @@
/*
* TSC-40 serial touchscreen driver. It should be compatible with
* TSC-10 and 25.
*
* Author: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
* License: GPLv2 as published by the FSF.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/serio.h>
#include <linux/init.h>
#define PACKET_LENGTH 5
struct tsc_ser {
struct input_dev *dev;
struct serio *serio;
u32 idx;
unsigned char data[PACKET_LENGTH];
char phys[32];
};
static void tsc_process_data(struct tsc_ser *ptsc)
{
struct input_dev *dev = ptsc->dev;
u8 *data = ptsc->data;
u32 x;
u32 y;
x = ((data[1] & 0x03) << 8) | data[2];
y = ((data[3] & 0x03) << 8) | data[4];
input_report_abs(dev, ABS_X, x);
input_report_abs(dev, ABS_Y, y);
input_report_key(dev, BTN_TOUCH, 1);
input_sync(dev);
}
static irqreturn_t tsc_interrupt(struct serio *serio,
unsigned char data, unsigned int flags)
{
struct tsc_ser *ptsc = serio_get_drvdata(serio);
struct input_dev *dev = ptsc->dev;
ptsc->data[ptsc->idx] = data;
switch (ptsc->idx++) {
case 0:
if (unlikely((data & 0x3e) != 0x10)) {
dev_dbg(&serio->dev,
"unsynchronized packet start (0x%02x)\n", data);
ptsc->idx = 0;
} else if (!(data & 0x01)) {
input_report_key(dev, BTN_TOUCH, 0);
input_sync(dev);
ptsc->idx = 0;
}
break;
case 1:
case 3:
if (unlikely(data & 0xfc)) {
dev_dbg(&serio->dev,
"unsynchronized data 0x%02x at offset %d\n",
data, ptsc->idx - 1);
ptsc->idx = 0;
}
break;
case 4:
tsc_process_data(ptsc);
ptsc->idx = 0;
break;
}
return IRQ_HANDLED;
}
static int tsc_connect(struct serio *serio, struct serio_driver *drv)
{
struct tsc_ser *ptsc;
struct input_dev *input_dev;
int error;
ptsc = kzalloc(sizeof(struct tsc_ser), GFP_KERNEL);
input_dev = input_allocate_device();
if (!ptsc || !input_dev) {
error = -ENOMEM;
goto fail1;
}
ptsc->serio = serio;
ptsc->dev = input_dev;
snprintf(ptsc->phys, sizeof(ptsc->phys), "%s/input0", serio->phys);
input_dev->name = "TSC-10/25/40 Serial TouchScreen";
input_dev->phys = ptsc->phys;
input_dev->id.bustype = BUS_RS232;
input_dev->id.vendor = SERIO_TSC40;
input_dev->id.product = 40;
input_dev->id.version = 0x0001;
input_dev->dev.parent = &serio->dev;
input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
__set_bit(BTN_TOUCH, input_dev->keybit);
input_set_abs_params(ptsc->dev, ABS_X, 0, 0x3ff, 0, 0);
input_set_abs_params(ptsc->dev, ABS_Y, 0, 0x3ff, 0, 0);
input_set_abs_params(ptsc->dev, ABS_PRESSURE, 0, 0, 0, 0);
serio_set_drvdata(serio, ptsc);
error = serio_open(serio, drv);
if (error)
goto fail2;
error = input_register_device(ptsc->dev);
if (error)
goto fail3;
return 0;
fail3:
serio_close(serio);
fail2:
serio_set_drvdata(serio, NULL);
fail1:
input_free_device(input_dev);
kfree(ptsc);
return error;
}
static void tsc_disconnect(struct serio *serio)
{
struct tsc_ser *ptsc = serio_get_drvdata(serio);
serio_close(serio);
input_unregister_device(ptsc->dev);
kfree(ptsc);
serio_set_drvdata(serio, NULL);
}
static struct serio_device_id tsc_serio_ids[] = {
{
.type = SERIO_RS232,
.proto = SERIO_TSC40,
.id = SERIO_ANY,
.extra = SERIO_ANY,
},
{ 0 }
};
MODULE_DEVICE_TABLE(serio, tsc_serio_ids);
#define DRIVER_DESC "TSC-10/25/40 serial touchscreen driver"
static struct serio_driver tsc_drv = {
.driver = {
.name = "tsc40",
},
.description = DRIVER_DESC,
.id_table = tsc_serio_ids,
.interrupt = tsc_interrupt,
.connect = tsc_connect,
.disconnect = tsc_disconnect,
};
static int __init tsc_ser_init(void)
{
return serio_register_driver(&tsc_drv);
}
module_init(tsc_ser_init);
static void __exit tsc_exit(void)
{
serio_unregister_driver(&tsc_drv);
}
module_exit(tsc_exit);
MODULE_AUTHOR("Sebastian Andrzej Siewior <bigeasy@linutronix.de>");
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL v2");

View file

@ -279,7 +279,7 @@ static int __devinit w90x900ts_probe(struct platform_device *pdev)
w90p910_ts->irq_num = platform_get_irq(pdev, 0);
if (request_irq(w90p910_ts->irq_num, w90p910_ts_interrupt,
IRQF_DISABLED, "w90p910ts", w90p910_ts)) {
0, "w90p910ts", w90p910_ts)) {
err = -EBUSY;
goto fail4;
}

View file

@ -367,6 +367,20 @@ static int w8001_command(struct w8001 *w8001, unsigned char command,
return rc;
}
static int w8001_open(struct input_dev *dev)
{
struct w8001 *w8001 = input_get_drvdata(dev);
return w8001_command(w8001, W8001_CMD_START, false);
}
static void w8001_close(struct input_dev *dev)
{
struct w8001 *w8001 = input_get_drvdata(dev);
w8001_command(w8001, W8001_CMD_STOP, false);
}
static int w8001_setup(struct w8001 *w8001)
{
struct input_dev *dev = w8001->dev;
@ -476,7 +490,7 @@ static int w8001_setup(struct w8001 *w8001)
strlcat(w8001->name, " Touchscreen", sizeof(w8001->name));
return w8001_command(w8001, W8001_CMD_START, false);
return 0;
}
/*
@ -487,12 +501,12 @@ static void w8001_disconnect(struct serio *serio)
{
struct w8001 *w8001 = serio_get_drvdata(serio);
input_get_device(w8001->dev);
input_unregister_device(w8001->dev);
serio_close(serio);
serio_set_drvdata(serio, NULL);
input_put_device(w8001->dev);
input_unregister_device(w8001->dev);
kfree(w8001);
serio_set_drvdata(serio, NULL);
}
/*
@ -536,6 +550,11 @@ static int w8001_connect(struct serio *serio, struct serio_driver *drv)
input_dev->id.version = 0x0100;
input_dev->dev.parent = &serio->dev;
input_dev->open = w8001_open;
input_dev->close = w8001_close;
input_set_drvdata(input_dev, w8001);
err = input_register_device(w8001->dev);
if (err)
goto fail3;

46
include/linux/bma150.h Normal file
View file

@ -0,0 +1,46 @@
/*
* Copyright (c) 2011 Bosch Sensortec GmbH
* Copyright (c) 2011 Unixphere
*
* 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.
*/
#ifndef _BMA150_H_
#define _BMA150_H_
#define BMA150_DRIVER "bma150"
struct bma150_cfg {
bool any_motion_int; /* Set to enable any-motion interrupt */
bool hg_int; /* Set to enable high-G interrupt */
bool lg_int; /* Set to enable low-G interrupt */
unsigned char any_motion_dur; /* Any-motion duration */
unsigned char any_motion_thres; /* Any-motion threshold */
unsigned char hg_hyst; /* High-G hysterisis */
unsigned char hg_dur; /* High-G duration */
unsigned char hg_thres; /* High-G threshold */
unsigned char lg_hyst; /* Low-G hysterisis */
unsigned char lg_dur; /* Low-G duration */
unsigned char lg_thres; /* Low-G threshold */
unsigned char range; /* BMA0150_RANGE_xxx (in G) */
unsigned char bandwidth; /* BMA0150_BW_xxx (in Hz) */
};
struct bma150_platform_data {
struct bma150_cfg cfg;
int (*irq_gpio_cfg)(void);
};
#endif /* _BMA150_H_ */

View file

@ -5,7 +5,7 @@
struct tsc2007_platform_data {
u16 model; /* 2007. */
u16 x_plate_ohms;
u16 x_plate_ohms; /* must be non-zero value */
u16 max_rt; /* max. resistance above which samples are ignored */
unsigned long poll_delay; /* delay (in ms) after pen-down event
before polling starts */

View file

@ -505,6 +505,7 @@ struct input_keymap_entry {
#define BTN_TOOL_FINGER 0x145
#define BTN_TOOL_MOUSE 0x146
#define BTN_TOOL_LENS 0x147
#define BTN_TOOL_QUINTTAP 0x148 /* Five fingers on trackpad */
#define BTN_TOUCH 0x14a
#define BTN_STYLUS 0x14b
#define BTN_STYLUS2 0x14c
@ -1609,7 +1610,7 @@ struct ff_device {
struct file *effect_owners[];
};
int input_ff_create(struct input_dev *dev, int max_effects);
int input_ff_create(struct input_dev *dev, unsigned int max_effects);
void input_ff_destroy(struct input_dev *dev);
int input_ff_event(struct input_dev *dev, unsigned int type, unsigned int code, int value);

View file

@ -1,5 +1,5 @@
/*
* Analog Devices ADP5589 I/O Expander and QWERTY Keypad Controller
* Analog Devices ADP5589/ADP5585 I/O Expander and QWERTY Keypad Controller
*
* Copyright 2010-2011 Analog Devices Inc.
*
@ -9,89 +9,9 @@
#ifndef _ADP5589_H
#define _ADP5589_H
#define ADP5589_ID 0x00
#define ADP5589_INT_STATUS 0x01
#define ADP5589_STATUS 0x02
#define ADP5589_FIFO_1 0x03
#define ADP5589_FIFO_2 0x04
#define ADP5589_FIFO_3 0x05
#define ADP5589_FIFO_4 0x06
#define ADP5589_FIFO_5 0x07
#define ADP5589_FIFO_6 0x08
#define ADP5589_FIFO_7 0x09
#define ADP5589_FIFO_8 0x0A
#define ADP5589_FIFO_9 0x0B
#define ADP5589_FIFO_10 0x0C
#define ADP5589_FIFO_11 0x0D
#define ADP5589_FIFO_12 0x0E
#define ADP5589_FIFO_13 0x0F
#define ADP5589_FIFO_14 0x10
#define ADP5589_FIFO_15 0x11
#define ADP5589_FIFO_16 0x12
#define ADP5589_GPI_INT_STAT_A 0x13
#define ADP5589_GPI_INT_STAT_B 0x14
#define ADP5589_GPI_INT_STAT_C 0x15
#define ADP5589_GPI_STATUS_A 0x16
#define ADP5589_GPI_STATUS_B 0x17
#define ADP5589_GPI_STATUS_C 0x18
#define ADP5589_RPULL_CONFIG_A 0x19
#define ADP5589_RPULL_CONFIG_B 0x1A
#define ADP5589_RPULL_CONFIG_C 0x1B
#define ADP5589_RPULL_CONFIG_D 0x1C
#define ADP5589_RPULL_CONFIG_E 0x1D
#define ADP5589_GPI_INT_LEVEL_A 0x1E
#define ADP5589_GPI_INT_LEVEL_B 0x1F
#define ADP5589_GPI_INT_LEVEL_C 0x20
#define ADP5589_GPI_EVENT_EN_A 0x21
#define ADP5589_GPI_EVENT_EN_B 0x22
#define ADP5589_GPI_EVENT_EN_C 0x23
#define ADP5589_GPI_INTERRUPT_EN_A 0x24
#define ADP5589_GPI_INTERRUPT_EN_B 0x25
#define ADP5589_GPI_INTERRUPT_EN_C 0x26
#define ADP5589_DEBOUNCE_DIS_A 0x27
#define ADP5589_DEBOUNCE_DIS_B 0x28
#define ADP5589_DEBOUNCE_DIS_C 0x29
#define ADP5589_GPO_DATA_OUT_A 0x2A
#define ADP5589_GPO_DATA_OUT_B 0x2B
#define ADP5589_GPO_DATA_OUT_C 0x2C
#define ADP5589_GPO_OUT_MODE_A 0x2D
#define ADP5589_GPO_OUT_MODE_B 0x2E
#define ADP5589_GPO_OUT_MODE_C 0x2F
#define ADP5589_GPIO_DIRECTION_A 0x30
#define ADP5589_GPIO_DIRECTION_B 0x31
#define ADP5589_GPIO_DIRECTION_C 0x32
#define ADP5589_UNLOCK1 0x33
#define ADP5589_UNLOCK2 0x34
#define ADP5589_EXT_LOCK_EVENT 0x35
#define ADP5589_UNLOCK_TIMERS 0x36
#define ADP5589_LOCK_CFG 0x37
#define ADP5589_RESET1_EVENT_A 0x38
#define ADP5589_RESET1_EVENT_B 0x39
#define ADP5589_RESET1_EVENT_C 0x3A
#define ADP5589_RESET2_EVENT_A 0x3B
#define ADP5589_RESET2_EVENT_B 0x3C
#define ADP5589_RESET_CFG 0x3D
#define ADP5589_PWM_OFFT_LOW 0x3E
#define ADP5589_PWM_OFFT_HIGH 0x3F
#define ADP5589_PWM_ONT_LOW 0x40
#define ADP5589_PWM_ONT_HIGH 0x41
#define ADP5589_PWM_CFG 0x42
#define ADP5589_CLOCK_DIV_CFG 0x43
#define ADP5589_LOGIC_1_CFG 0x44
#define ADP5589_LOGIC_2_CFG 0x45
#define ADP5589_LOGIC_FF_CFG 0x46
#define ADP5589_LOGIC_INT_EVENT_EN 0x47
#define ADP5589_POLL_PTIME_CFG 0x48
#define ADP5589_PIN_CONFIG_A 0x49
#define ADP5589_PIN_CONFIG_B 0x4A
#define ADP5589_PIN_CONFIG_C 0x4B
#define ADP5589_PIN_CONFIG_D 0x4C
#define ADP5589_GENERAL_CFG 0x4D
#define ADP5589_INT_EN 0x4E
#define ADP5589_DEVICE_ID_MASK 0xF
/* Put one of these structures in i2c_board_info platform_data */
/*
* ADP5589 specific GPI and Keymap defines
*/
#define ADP5589_KEYMAPSIZE 88
@ -127,6 +47,35 @@
#define ADP5589_GPIMAPSIZE_MAX (ADP5589_GPI_PIN_END - ADP5589_GPI_PIN_BASE + 1)
/*
* ADP5585 specific GPI and Keymap defines
*/
#define ADP5585_KEYMAPSIZE 30
#define ADP5585_GPI_PIN_ROW0 37
#define ADP5585_GPI_PIN_ROW1 38
#define ADP5585_GPI_PIN_ROW2 39
#define ADP5585_GPI_PIN_ROW3 40
#define ADP5585_GPI_PIN_ROW4 41
#define ADP5585_GPI_PIN_ROW5 42
#define ADP5585_GPI_PIN_COL0 43
#define ADP5585_GPI_PIN_COL1 44
#define ADP5585_GPI_PIN_COL2 45
#define ADP5585_GPI_PIN_COL3 46
#define ADP5585_GPI_PIN_COL4 47
#define GPI_LOGIC 48
#define ADP5585_GPI_PIN_ROW_BASE ADP5585_GPI_PIN_ROW0
#define ADP5585_GPI_PIN_ROW_END ADP5585_GPI_PIN_ROW5
#define ADP5585_GPI_PIN_COL_BASE ADP5585_GPI_PIN_COL0
#define ADP5585_GPI_PIN_COL_END ADP5585_GPI_PIN_COL4
#define ADP5585_GPI_PIN_BASE ADP5585_GPI_PIN_ROW_BASE
#define ADP5585_GPI_PIN_END ADP5585_GPI_PIN_COL_END
#define ADP5585_GPIMAPSIZE_MAX (ADP5585_GPI_PIN_END - ADP5585_GPI_PIN_BASE + 1)
struct adp5589_gpi_map {
unsigned short pin;
unsigned short sw_evt;
@ -159,7 +108,7 @@ struct adp5589_gpi_map {
#define RESET2_POL_HIGH (1 << 7)
#define RESET2_POL_LOW (0 << 7)
/* Mask Bits:
/* ADP5589 Mask Bits:
* C C C C C C C C C C C | R R R R R R R R
* 1 9 8 7 6 5 4 3 2 1 0 | 7 6 5 4 3 2 1 0
* 0
@ -168,18 +117,44 @@ struct adp5589_gpi_map {
* 8 7 6 5 4 3 2 1 0 9 8 | 7 6 5 4 3 2 1 0
*/
#define ADP_ROW(x) (1 << (x))
#define ADP_COL(x) (1 << (x + 8))
#define ADP_ROW(x) (1 << (x))
#define ADP_COL(x) (1 << (x + 8))
#define ADP5589_ROW_MASK 0xFF
#define ADP5589_COL_MASK 0xFF
#define ADP5589_COL_SHIFT 8
#define ADP5589_MAX_ROW_NUM 7
#define ADP5589_MAX_COL_NUM 10
/* ADP5585 Mask Bits:
* C C C C C | R R R R R R
* 4 3 2 1 0 | 5 4 3 2 1 0
*
* ---- BIT -- -----------
* 1 0 0 0 0 | 0 0 0 0 0 0
* 0 9 8 7 6 | 5 4 3 2 1 0
*/
#define ADP5585_ROW_MASK 0x3F
#define ADP5585_COL_MASK 0x1F
#define ADP5585_ROW_SHIFT 0
#define ADP5585_COL_SHIFT 6
#define ADP5585_MAX_ROW_NUM 5
#define ADP5585_MAX_COL_NUM 4
#define ADP5585_ROW(x) (1 << ((x) & ADP5585_ROW_MASK))
#define ADP5585_COL(x) (1 << (((x) & ADP5585_COL_MASK) + ADP5585_COL_SHIFT))
/* Put one of these structures in i2c_board_info platform_data */
struct adp5589_kpad_platform_data {
unsigned keypad_en_mask; /* Keypad (Rows/Columns) enable mask */
const unsigned short *keymap; /* Pointer to keymap */
unsigned short keymapsize; /* Keymap size */
bool repeat; /* Enable key repeat */
bool en_keylock; /* Enable key lock feature */
unsigned char unlock_key1; /* Unlock Key 1 */
unsigned char unlock_key2; /* Unlock Key 2 */
unsigned char unlock_timer; /* Time in seconds [0..7] between the two unlock keys 0=disable */
bool en_keylock; /* Enable key lock feature (ADP5589 only)*/
unsigned char unlock_key1; /* Unlock Key 1 (ADP5589 only) */
unsigned char unlock_key2; /* Unlock Key 2 (ADP5589 only) */
unsigned char unlock_timer; /* Time in seconds [0..7] between the two unlock keys 0=disable (ADP5589 only) */
unsigned char scan_cycle_time; /* Time between consecutive scan cycles */
unsigned char reset_cfg; /* Reset config */
unsigned short reset1_key_1; /* Reset Key 1 */

View file

@ -30,8 +30,9 @@ struct adxl34x_platform_data {
* Y, or Z participation in Tap detection. A '0' excludes the
* selected axis from participation in Tap detection.
* Setting the SUPPRESS bit suppresses Double Tap detection if
* acceleration greater than tap_threshold is present between
* taps.
* acceleration greater than tap_threshold is present during the
* tap_latency period, i.e. after the first tap but before the
* opening of the second tap window.
*/
#define ADXL_SUPPRESS (1 << 3)
@ -226,13 +227,13 @@ struct adxl34x_platform_data {
* detection will begin and prevent the detection of activity. This
* bit serially links the activity and inactivity functions. When '0'
* the inactivity and activity functions are concurrent. Additional
* information can be found in the Application section under Link
* Mode.
* information can be found in the ADXL34x datasheet's Application
* section under Link Mode.
* AUTO_SLEEP: A '1' sets the ADXL34x to switch to Sleep Mode
* when inactivity (acceleration has been below inactivity_threshold
* for at least inactivity_time) is detected and the LINK bit is set.
* A '0' disables automatic switching to Sleep Mode. See SLEEP
* for further description.
* A '0' disables automatic switching to Sleep Mode. See the
* Sleep Bit section of the ADXL34x datasheet for more information.
*/
#define ADXL_LINK (1 << 5)
@ -266,6 +267,12 @@ struct adxl34x_platform_data {
u8 watermark;
/*
* When acceleration measurements are received from the ADXL34x
* events are sent to the event subsystem. The following settings
* select the event type and event code for new x, y and z axis data
* respectively.
*/
u32 ev_type; /* EV_ABS or EV_REL */
u32 ev_code_x; /* ABS_X,Y,Z or REL_X,Y,Z */
@ -289,7 +296,7 @@ struct adxl34x_platform_data {
u32 ev_code_act_inactivity; /* EV_KEY */
/*
* Use ADXL34x INT2 instead of INT1
* Use ADXL34x INT2 pin instead of INT1 pin for interrupt output
*/
u8 use_int2;

View file

@ -199,5 +199,6 @@ static inline void serio_continue_rx(struct serio *serio)
#define SERIO_DYNAPRO 0x3a
#define SERIO_HAMPSHIRE 0x3b
#define SERIO_PS2MULT 0x3c
#define SERIO_TSC40 0x3d
#endif

View file

@ -68,7 +68,7 @@ struct uinput_device {
unsigned char head;
unsigned char tail;
struct input_event buff[UINPUT_BUFFER_SIZE];
int ff_effects_max;
unsigned int ff_effects_max;
struct uinput_request *requests[UINPUT_NUM_REQUESTS];
wait_queue_head_t requests_waitq;