Commit 554738da authored by Dmitry Torokhov's avatar Dmitry Torokhov

Merge branch 'next' into for-linus

Conflicts:
	include/linux/input.h
parents 7b4b3068 a6d38f88
...@@ -303,6 +303,10 @@ X!Idrivers/video/console/fonts.c ...@@ -303,6 +303,10 @@ X!Idrivers/video/console/fonts.c
!Edrivers/input/input.c !Edrivers/input/input.c
!Edrivers/input/ff-core.c !Edrivers/input/ff-core.c
!Edrivers/input/ff-memless.c !Edrivers/input/ff-memless.c
</sect1>
<sect1><title>Multitouch Library</title>
!Iinclude/linux/input/mt.h
!Edrivers/input/input-mt.c
</sect1> </sect1>
<sect1><title>Polled input devices</title> <sect1><title>Polled input devices</title>
!Iinclude/linux/input-polldev.h !Iinclude/linux/input-polldev.h
......
Kernel driver for CMA3000-D0x
============================
Supported chips:
* VTI CMA3000-D0x
Datasheet:
CMA3000-D0X Product Family Specification 8281000A.02.pdf
<http://www.vti.fi/en/>
Author: Hemanth V <hemanthv@ti.com>
Description
-----------
CMA3000 Tri-axis accelerometer supports Motion detect, Measurement and
Free fall modes.
Motion Detect Mode: Its the low power mode where interrupts are generated only
when motion exceeds the defined thresholds.
Measurement Mode: This mode is used to read the acceleration data on X,Y,Z
axis and supports 400, 100, 40 Hz sample frequency.
Free fall Mode: This mode is intended to save system resources.
Threshold values: Chip supports defining threshold values for above modes
which includes time and g value. Refer product specifications for more details.
CMA3000 chip supports mutually exclusive I2C and SPI interfaces for
communication, currently the driver supports I2C based communication only.
Initial configuration for bus mode is set in non volatile memory and can later
be modified through bus interface command.
Driver reports acceleration data through input subsystem. It generates ABS_MISC
event with value 1 when free fall is detected.
Platform data need to be configured for initial default values.
Platform Data
-------------
fuzz_x: Noise on X Axis
fuzz_y: Noise on Y Axis
fuzz_z: Noise on Z Axis
g_range: G range in milli g i.e 2000 or 8000
mode: Default Operating mode
mdthr: Motion detect g range threshold value
mdfftmr: Motion detect and free fall time threshold value
ffthr: Free fall g range threshold value
Input Interface
--------------
Input driver version is 1.0.0
Input device ID: bus 0x18 vendor 0x0 product 0x0 version 0x0
Input device name: "cma3000-accelerometer"
Supported events:
Event type 0 (Sync)
Event type 3 (Absolute)
Event code 0 (X)
Value 47
Min -8000
Max 8000
Fuzz 200
Event code 1 (Y)
Value -28
Min -8000
Max 8000
Fuzz 200
Event code 2 (Z)
Value 905
Min -8000
Max 8000
Fuzz 200
Event code 40 (Misc)
Value 0
Min 0
Max 1
Event type 4 (Misc)
Register/Platform parameters Description
----------------------------------------
mode:
0: power down mode
1: 100 Hz Measurement mode
2: 400 Hz Measurement mode
3: 40 Hz Measurement mode
4: Motion Detect mode (default)
5: 100 Hz Free fall mode
6: 40 Hz Free fall mode
7: Power off mode
grange:
2000: 2000 mg or 2G Range
8000: 8000 mg or 8G Range
mdthr:
X: X * 71mg (8G Range)
X: X * 18mg (2G Range)
mdfftmr:
X: (X & 0x70) * 100 ms (MDTMR)
(X & 0x0F) * 2.5 ms (FFTMR 400 Hz)
(X & 0x0F) * 10 ms (FFTMR 100 Hz)
ffthr:
X: (X >> 2) * 18mg (2G Range)
X: (X & 0x0F) * 71 mg (8G Range)
Multi-touch (MT) Protocol Multi-touch (MT) Protocol
------------------------- -------------------------
Copyright (C) 2009 Henrik Rydberg <rydberg@euromail.se> Copyright (C) 2009-2010 Henrik Rydberg <rydberg@euromail.se>
Introduction Introduction
...@@ -161,19 +161,24 @@ against the glass. The inner region will increase, and in general, the ...@@ -161,19 +161,24 @@ against the glass. The inner region will increase, and in general, the
ratio ABS_MT_TOUCH_MAJOR / ABS_MT_WIDTH_MAJOR, which is always smaller than ratio ABS_MT_TOUCH_MAJOR / ABS_MT_WIDTH_MAJOR, which is always smaller than
unity, is related to the contact pressure. For pressure-based devices, unity, is related to the contact pressure. For pressure-based devices,
ABS_MT_PRESSURE may be used to provide the pressure on the contact area ABS_MT_PRESSURE may be used to provide the pressure on the contact area
instead. instead. Devices capable of contact hovering can use ABS_MT_DISTANCE to
indicate the distance between the contact and the surface.
In addition to the MAJOR parameters, the oval shape of the contact can be In addition to the MAJOR parameters, the oval shape of the contact can be
described by adding the MINOR parameters, such that MAJOR and MINOR are the described by adding the MINOR parameters, such that MAJOR and MINOR are the
major and minor axis of an ellipse. Finally, the orientation of the oval major and minor axis of an ellipse. Finally, the orientation of the oval
shape can be describe with the ORIENTATION parameter. shape can be describe with the ORIENTATION parameter.
For type A devices, further specification of the touch shape is possible
via ABS_MT_BLOB_ID.
The ABS_MT_TOOL_TYPE may be used to specify whether the touching tool is a The ABS_MT_TOOL_TYPE may be used to specify whether the touching tool is a
contact or a pen or something else. Devices with more granular information finger or a pen or something else. Finally, the ABS_MT_TRACKING_ID event
may specify general shapes as blobs, i.e., as a sequence of rectangular may be used to track identified contacts over time [5].
shapes grouped together by an ABS_MT_BLOB_ID. Finally, for the few devices
that currently support it, the ABS_MT_TRACKING_ID event may be used to In the type B protocol, ABS_MT_TOOL_TYPE and ABS_MT_TRACKING_ID are
report contact tracking from hardware [5]. implicitly handled by input core; drivers should instead call
input_mt_report_slot_state().
Event Semantics Event Semantics
...@@ -213,6 +218,12 @@ The pressure, in arbitrary units, on the contact area. May be used instead ...@@ -213,6 +218,12 @@ The pressure, in arbitrary units, on the contact area. May be used instead
of TOUCH and WIDTH for pressure-based devices or any device with a spatial of TOUCH and WIDTH for pressure-based devices or any device with a spatial
signal intensity distribution. signal intensity distribution.
ABS_MT_DISTANCE
The distance, in surface units, between the contact and the surface. Zero
distance means the contact is touching the surface. A positive number means
the contact is hovering above the surface.
ABS_MT_ORIENTATION ABS_MT_ORIENTATION
The orientation of the ellipse. The value should describe a signed quarter The orientation of the ellipse. The value should describe a signed quarter
...@@ -240,21 +251,24 @@ ABS_MT_TOOL_TYPE ...@@ -240,21 +251,24 @@ ABS_MT_TOOL_TYPE
The type of approaching tool. A lot of kernel drivers cannot distinguish The type of approaching tool. A lot of kernel drivers cannot distinguish
between different tool types, such as a finger or a pen. In such cases, the between different tool types, such as a finger or a pen. In such cases, the
event should be omitted. The protocol currently supports MT_TOOL_FINGER and event should be omitted. The protocol currently supports MT_TOOL_FINGER and
MT_TOOL_PEN [2]. MT_TOOL_PEN [2]. For type B devices, this event is handled by input core;
drivers should instead use input_mt_report_slot_state().
ABS_MT_BLOB_ID ABS_MT_BLOB_ID
The BLOB_ID groups several packets together into one arbitrarily shaped The BLOB_ID groups several packets together into one arbitrarily shaped
contact. This is a low-level anonymous grouping for type A devices, and contact. The sequence of points forms a polygon which defines the shape of
the contact. This is a low-level anonymous grouping for type A devices, and
should not be confused with the high-level trackingID [5]. Most type A should not be confused with the high-level trackingID [5]. Most type A
devices do not have blob capability, so drivers can safely omit this event. devices do not have blob capability, so drivers can safely omit this event.
ABS_MT_TRACKING_ID ABS_MT_TRACKING_ID
The TRACKING_ID identifies an initiated contact throughout its life cycle The TRACKING_ID identifies an initiated contact throughout its life cycle
[5]. This event is mandatory for type B devices. The value range of the [5]. The value range of the TRACKING_ID should be large enough to ensure
TRACKING_ID should be large enough to ensure unique identification of a unique identification of a contact maintained over an extended period of
contact maintained over an extended period of time. time. For type B devices, this event is handled by input core; drivers
should instead use input_mt_report_slot_state().
Event Computation Event Computation
...@@ -301,18 +315,19 @@ and with ORIENTATION, one can detect twisting of fingers. ...@@ -301,18 +315,19 @@ and with ORIENTATION, one can detect twisting of fingers.
Notes Notes
----- -----
In order to stay compatible with existing applications, the data In order to stay compatible with existing applications, the data reported
reported in a finger packet must not be recognized as single-touch in a finger packet must not be recognized as single-touch events.
events. In addition, all finger data must bypass input filtering,
since subsequent events of the same type refer to different fingers. For type A devices, all finger data bypasses input filtering, since
subsequent events of the same type refer to different fingers.
The first kernel driver to utilize the MT protocol is the bcm5974 driver, For example usage of the type A protocol, see the bcm5974 driver. For
where examples can be found. example usage of the type B protocol, see the hid-egalax driver.
[1] With the extension ABS_MT_APPROACH_X and ABS_MT_APPROACH_Y, the [1] With the extension ABS_MT_APPROACH_X and ABS_MT_APPROACH_Y, the
difference between the contact position and the approaching tool position difference between the contact position and the approaching tool position
could be used to derive tilt. could be used to derive tilt.
[2] The list can of course be extended. [2] The list can of course be extended.
[3] Multitouch X driver project: http://bitmath.org/code/multitouch/. [3] The mtdev project: http://bitmath.org/code/mtdev/.
[4] See the section on event computation. [4] See the section on event computation.
[5] See the section on finger tracking. [5] See the section on finger tracking.
...@@ -3020,8 +3020,10 @@ F: drivers/input/ ...@@ -3020,8 +3020,10 @@ F: drivers/input/
INPUT MULTITOUCH (MT) PROTOCOL INPUT MULTITOUCH (MT) PROTOCOL
M: Henrik Rydberg <rydberg@euromail.se> M: Henrik Rydberg <rydberg@euromail.se>
L: linux-input@vger.kernel.org L: linux-input@vger.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/rydberg/input-mt.git
S: Maintained S: Maintained
F: Documentation/input/multi-touch-protocol.txt F: Documentation/input/multi-touch-protocol.txt
F: drivers/input/input-mt.c
K: \b(ABS|SYN)_MT_ K: \b(ABS|SYN)_MT_
INTEL IDLE DRIVER INTEL IDLE DRIVER
......
/*
* Copyright (C) 2010 ST Microelectronics
* Rajeev Kumar<rajeev-dlh.kumar@st.com>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
#ifndef __PLAT_KEYBOARD_H
#define __PLAT_KEYBOARD_H
#include <linux/bitops.h>
#include <linux/input.h>
#include <linux/input/matrix_keypad.h>
#include <linux/types.h>
#define DECLARE_KEYMAP(_name) \
int _name[] = { \
KEY(0, 0, KEY_ESC), \
KEY(0, 1, KEY_1), \
KEY(0, 2, KEY_2), \
KEY(0, 3, KEY_3), \
KEY(0, 4, KEY_4), \
KEY(0, 5, KEY_5), \
KEY(0, 6, KEY_6), \
KEY(0, 7, KEY_7), \
KEY(0, 8, KEY_8), \
KEY(1, 0, KEY_9), \
KEY(1, 1, KEY_MINUS), \
KEY(1, 2, KEY_EQUAL), \
KEY(1, 3, KEY_BACKSPACE), \
KEY(1, 4, KEY_TAB), \
KEY(1, 5, KEY_Q), \
KEY(1, 6, KEY_W), \
KEY(1, 7, KEY_E), \
KEY(1, 8, KEY_R), \
KEY(2, 0, KEY_T), \
KEY(2, 1, KEY_Y), \
KEY(2, 2, KEY_U), \
KEY(2, 3, KEY_I), \
KEY(2, 4, KEY_O), \
KEY(2, 5, KEY_P), \
KEY(2, 6, KEY_LEFTBRACE), \
KEY(2, 7, KEY_RIGHTBRACE), \
KEY(2, 8, KEY_ENTER), \
KEY(3, 0, KEY_LEFTCTRL), \
KEY(3, 1, KEY_A), \
KEY(3, 2, KEY_S), \
KEY(3, 3, KEY_D), \
KEY(3, 4, KEY_F), \
KEY(3, 5, KEY_G), \
KEY(3, 6, KEY_H), \
KEY(3, 7, KEY_J), \
KEY(3, 8, KEY_K), \
KEY(4, 0, KEY_L), \
KEY(4, 1, KEY_SEMICOLON), \
KEY(4, 2, KEY_APOSTROPHE), \
KEY(4, 3, KEY_GRAVE), \
KEY(4, 4, KEY_LEFTSHIFT), \
KEY(4, 5, KEY_BACKSLASH), \
KEY(4, 6, KEY_Z), \
KEY(4, 7, KEY_X), \
KEY(4, 8, KEY_C), \
KEY(4, 0, KEY_L), \
KEY(4, 1, KEY_SEMICOLON), \
KEY(4, 2, KEY_APOSTROPHE), \
KEY(4, 3, KEY_GRAVE), \
KEY(4, 4, KEY_LEFTSHIFT), \
KEY(4, 5, KEY_BACKSLASH), \
KEY(4, 6, KEY_Z), \
KEY(4, 7, KEY_X), \
KEY(4, 8, KEY_C), \
KEY(4, 0, KEY_L), \
KEY(4, 1, KEY_SEMICOLON), \
KEY(4, 2, KEY_APOSTROPHE), \
KEY(4, 3, KEY_GRAVE), \
KEY(4, 4, KEY_LEFTSHIFT), \
KEY(4, 5, KEY_BACKSLASH), \
KEY(4, 6, KEY_Z), \
KEY(4, 7, KEY_X), \
KEY(4, 8, KEY_C), \
KEY(5, 0, KEY_V), \
KEY(5, 1, KEY_B), \
KEY(5, 2, KEY_N), \
KEY(5, 3, KEY_M), \
KEY(5, 4, KEY_COMMA), \
KEY(5, 5, KEY_DOT), \
KEY(5, 6, KEY_SLASH), \
KEY(5, 7, KEY_RIGHTSHIFT), \
KEY(5, 8, KEY_KPASTERISK), \
KEY(6, 0, KEY_LEFTALT), \
KEY(6, 1, KEY_SPACE), \
KEY(6, 2, KEY_CAPSLOCK), \
KEY(6, 3, KEY_F1), \
KEY(6, 4, KEY_F2), \
KEY(6, 5, KEY_F3), \
KEY(6, 6, KEY_F4), \
KEY(6, 7, KEY_F5), \
KEY(6, 8, KEY_F6), \
KEY(7, 0, KEY_F7), \
KEY(7, 1, KEY_F8), \
KEY(7, 2, KEY_F9), \
KEY(7, 3, KEY_F10), \
KEY(7, 4, KEY_NUMLOCK), \
KEY(7, 5, KEY_SCROLLLOCK), \
KEY(7, 6, KEY_KP7), \
KEY(7, 7, KEY_KP8), \
KEY(7, 8, KEY_KP9), \
KEY(8, 0, KEY_KPMINUS), \
KEY(8, 1, KEY_KP4), \
KEY(8, 2, KEY_KP5), \
KEY(8, 3, KEY_KP6), \
KEY(8, 4, KEY_KPPLUS), \
KEY(8, 5, KEY_KP1), \
KEY(8, 6, KEY_KP2), \
KEY(8, 7, KEY_KP3), \
KEY(8, 8, KEY_KP0), \
}
/**
* struct kbd_platform_data - spear keyboard platform data
* keymap: pointer to keymap data (table and size)
* rep: enables key autorepeat
*
* This structure is supposed to be used by platform code to supply
* keymaps to drivers that implement keyboards.
*/
struct kbd_platform_data {
const struct matrix_keymap_data *keymap;
bool rep;
};
/* This function is used to set platform data field of pdev->dev */
static inline void
kbd_set_plat_data(struct platform_device *pdev, struct kbd_platform_data *data)
{
pdev->dev.platform_data = data;
}
#endif /* __PLAT_KEYBOARD_H */
...@@ -154,7 +154,8 @@ config HID_EGALAX ...@@ -154,7 +154,8 @@ config HID_EGALAX
tristate "eGalax multi-touch panel" tristate "eGalax multi-touch panel"
depends on USB_HID depends on USB_HID
---help--- ---help---
Support for the eGalax dual-touch panel. Support for the eGalax dual-touch panels, including the
Joojoo and Wetab tablets.
config HID_ELECOM config HID_ELECOM
tristate "ELECOM BM084 bluetooth mouse" tristate "ELECOM BM084 bluetooth mouse"
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/usb.h> #include <linux/usb.h>
#include <linux/input/mt.h>
MODULE_AUTHOR("Stephane Chatty <chatty@enac.fr>"); MODULE_AUTHOR("Stephane Chatty <chatty@enac.fr>");
MODULE_DESCRIPTION("3M PCT multitouch panels"); MODULE_DESCRIPTION("3M PCT multitouch panels");
...@@ -27,8 +28,6 @@ MODULE_LICENSE("GPL"); ...@@ -27,8 +28,6 @@ MODULE_LICENSE("GPL");
#include "hid-ids.h" #include "hid-ids.h"
#define MAX_SLOTS 60 #define MAX_SLOTS 60
#define MAX_TRKID USHRT_MAX
#define MAX_EVENTS 360
/* estimated signal-to-noise ratios */ /* estimated signal-to-noise ratios */
#define SN_MOVE 2048 #define SN_MOVE 2048
...@@ -36,14 +35,11 @@ MODULE_LICENSE("GPL"); ...@@ -36,14 +35,11 @@ MODULE_LICENSE("GPL");
struct mmm_finger { struct mmm_finger {
__s32 x, y, w, h; __s32 x, y, w, h;
__u16 id;
bool prev_touch;
bool touch, valid; bool touch, valid;
}; };
struct mmm_data { struct mmm_data {
struct mmm_finger f[MAX_SLOTS]; struct mmm_finger f[MAX_SLOTS];
__u16 id;
__u8 curid; __u8 curid;
__u8 nexp, nreal; __u8 nexp, nreal;
bool touch, valid; bool touch, valid;
...@@ -117,14 +113,7 @@ static int mmm_input_mapping(struct hid_device *hdev, struct hid_input *hi, ...@@ -117,14 +113,7 @@ static int mmm_input_mapping(struct hid_device *hdev, struct hid_input *hi,
0, 1, 0, 0); 0, 1, 0, 0);
return 1; return 1;
case HID_DG_CONTACTID: case HID_DG_CONTACTID:
field->logical_maximum = MAX_TRKID; input_mt_init_slots(hi->input, MAX_SLOTS);
hid_map_usage(hi, usage, bit, max,
EV_ABS, ABS_MT_TRACKING_ID);
input_set_abs_params(hi->input, ABS_MT_TRACKING_ID,
0, MAX_TRKID, 0, 0);
if (!hi->input->mt)
input_mt_create_slots(hi->input, MAX_SLOTS);
input_set_events_per_packet(hi->input, MAX_EVENTS);
return 1; return 1;
} }
/* let hid-input decide for the others */ /* let hid-input decide for the others */
...@@ -154,7 +143,6 @@ static int mmm_input_mapped(struct hid_device *hdev, struct hid_input *hi, ...@@ -154,7 +143,6 @@ static int mmm_input_mapped(struct hid_device *hdev, struct hid_input *hi,
*/ */
static void mmm_filter_event(struct mmm_data *md, struct input_dev *input) static void mmm_filter_event(struct mmm_data *md, struct input_dev *input)
{ {
struct mmm_finger *oldest = 0;
int i; int i;
for (i = 0; i < MAX_SLOTS; ++i) { for (i = 0; i < MAX_SLOTS; ++i) {
struct mmm_finger *f = &md->f[i]; struct mmm_finger *f = &md->f[i];
...@@ -163,6 +151,7 @@ static void mmm_filter_event(struct mmm_data *md, struct input_dev *input) ...@@ -163,6 +151,7 @@ static void mmm_filter_event(struct mmm_data *md, struct input_dev *input)
continue; continue;
} }
input_mt_slot(input, i); input_mt_slot(input, i);
input_mt_report_slot_state(input, MT_TOOL_FINGER, f->touch);
if (f->touch) { if (f->touch) {
/* this finger is on the screen */ /* this finger is on the screen */
int wide = (f->w > f->h); int wide = (f->w > f->h);
...@@ -170,33 +159,16 @@ static void mmm_filter_event(struct mmm_data *md, struct input_dev *input) ...@@ -170,33 +159,16 @@ static void mmm_filter_event(struct mmm_data *md, struct input_dev *input)
int major = max(f->w, f->h) >> 1; int major = max(f->w, f->h) >> 1;
int minor = min(f->w, f->h) >> 1; int minor = min(f->w, f->h) >> 1;
if (!f->prev_touch)
f->id = md->id++;
input_event(input, EV_ABS, ABS_MT_TRACKING_ID, f->id);
input_event(input, EV_ABS, ABS_MT_POSITION_X, f->x); input_event(input, EV_ABS, ABS_MT_POSITION_X, f->x);
input_event(input, EV_ABS, ABS_MT_POSITION_Y, f->y); input_event(input, EV_ABS, ABS_MT_POSITION_Y, f->y);
input_event(input, EV_ABS, ABS_MT_ORIENTATION, wide); input_event(input, EV_ABS, ABS_MT_ORIENTATION, wide);
input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, major); input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, major);
input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR, minor); input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR, minor);
/* touchscreen emulation: pick the oldest contact */
if (!oldest || ((f->id - oldest->id) & (SHRT_MAX + 1)))
oldest = f;
} else {
/* this finger took off the screen */
input_event(input, EV_ABS, ABS_MT_TRACKING_ID, -1);
} }
f->prev_touch = f->touch;
f->valid = 0; f->valid = 0;
} }
/* touchscreen emulation */ input_mt_report_pointer_emulation(input, true);
if (oldest) {
input_event(input, EV_KEY, BTN_TOUCH, 1);
input_event(input, EV_ABS, ABS_X, oldest->x);
input_event(input, EV_ABS, ABS_Y, oldest->y);
} else {
input_event(input, EV_KEY, BTN_TOUCH, 0);
}
input_sync(input); input_sync(input);
} }
......
...@@ -1300,6 +1300,9 @@ static const struct hid_device_id hid_blacklist[] = { ...@@ -1300,6 +1300,9 @@ static const struct hid_device_id hid_blacklist[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0006) }, { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0006) },
{ HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH) }, { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH) },
{ HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH1) }, { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH1) },
{ HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH3) },
{ HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH4) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_BM084) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_BM084) },
{ HID_USB_DEVICE(USB_VENDOR_ID_EZKEY, USB_DEVICE_ID_BTC_8193) }, { HID_USB_DEVICE(USB_VENDOR_ID_EZKEY, USB_DEVICE_ID_BTC_8193) },
{ HID_USB_DEVICE(USB_VENDOR_ID_GAMERON, USB_DEVICE_ID_GAMERON_DUAL_PSX_ADAPTOR) }, { HID_USB_DEVICE(USB_VENDOR_ID_GAMERON, USB_DEVICE_ID_GAMERON_DUAL_PSX_ADAPTOR) },
......
...@@ -2,6 +2,8 @@ ...@@ -2,6 +2,8 @@
* HID driver for eGalax dual-touch panels * HID driver for eGalax dual-touch panels
* *
* Copyright (c) 2010 Stephane Chatty <chatty@enac.fr> * Copyright (c) 2010 Stephane Chatty <chatty@enac.fr>
* Copyright (c) 2010 Henrik Rydberg <rydberg@euromail.se>
* Copyright (c) 2010 Canonical, Ltd.
* *
*/ */
...@@ -16,6 +18,7 @@ ...@@ -16,6 +18,7 @@
#include <linux/hid.h> #include <linux/hid.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/usb.h> #include <linux/usb.h>
#include <linux/input/mt.h>
#include <linux/slab.h> #include <linux/slab.h>
#include "usbhid/usbhid.h" #include "usbhid/usbhid.h"
...@@ -25,38 +28,53 @@ MODULE_LICENSE("GPL"); ...@@ -25,38 +28,53 @@ MODULE_LICENSE("GPL");
#include "hid-ids.h" #include "hid-ids.h"
#define MAX_SLOTS 2
/* estimated signal-to-noise ratios */
#define SN_MOVE 4096
#define SN_PRESSURE 32
struct egalax_data { struct egalax_data {
__u16 x, y, z; int valid;
__u8 id; int slot;
bool first; /* is this the first finger in the frame? */ int touch;
bool valid; /* valid finger data, or just placeholder? */ int x, y, z;
bool activity; /* at least one active finger previously? */
__u16 lastx, lasty, lastz; /* latest valid (x, y, z) in the frame */
}; };
static void set_abs(struct input_dev *input, unsigned int code,
struct hid_field *field, int snratio)
{
int fmin = field->logical_minimum;
int fmax = field->logical_maximum;
int fuzz = snratio ? (fmax - fmin) / snratio : 0;
input_set_abs_params(input, code, fmin, fmax, fuzz, 0);
}
static int egalax_input_mapping(struct hid_device *hdev, struct hid_input *hi, static int egalax_input_mapping(struct hid_device *hdev, struct hid_input *hi,
struct hid_field *field, struct hid_usage *usage, struct hid_field *field, struct hid_usage *usage,
unsigned long **bit, int *max) unsigned long **bit, int *max)
{ {
struct input_dev *input = hi->input;
switch (usage->hid & HID_USAGE_PAGE) { switch (usage->hid & HID_USAGE_PAGE) {
case HID_UP_GENDESK: case HID_UP_GENDESK:
switch (usage->hid) { switch (usage->hid) {
case HID_GD_X: case HID_GD_X:
field->logical_maximum = 32760;
hid_map_usage(hi, usage, bit, max, hid_map_usage(hi, usage, bit, max,
EV_ABS, ABS_MT_POSITION_X); EV_ABS, ABS_MT_POSITION_X);
set_abs(input, ABS_MT_POSITION_X, field, SN_MOVE);
/* touchscreen emulation */ /* touchscreen emulation */
input_set_abs_params(hi->input, ABS_X, set_abs(input, ABS_X, field, SN_MOVE);
field->logical_minimum,
field->logical_maximum, 0, 0);
return 1; return 1;
case HID_GD_Y: case HID_GD_Y:
field->logical_maximum = 32760;
hid_map_usage(hi, usage, bit, max, hid_map_usage(hi, usage, bit, max,
EV_ABS, ABS_MT_POSITION_Y); EV_ABS, ABS_MT_POSITION_Y);
set_abs(input, ABS_MT_POSITION_Y, field, SN_MOVE);
/* touchscreen emulation */ /* touchscreen emulation */
input_set_abs_params(hi->input, ABS_Y, set_abs(input, ABS_Y, field, SN_MOVE);
field->logical_minimum,
field->logical_maximum, 0, 0);
return 1; return 1;
} }
return 0; return 0;
...@@ -66,6 +84,7 @@ static int egalax_input_mapping(struct hid_device *hdev, struct hid_input *hi, ...@@ -66,6 +84,7 @@ static int egalax_input_mapping(struct hid_device *hdev, struct hid_input *hi,
case HID_DG_TIPSWITCH: case HID_DG_TIPSWITCH:
/* touchscreen emulation */ /* touchscreen emulation */
hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH); hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH);
input_set_capability(input, EV_KEY, BTN_TOUCH);
return 1; return 1;
case HID_DG_INRANGE: case HID_DG_INRANGE:
case HID_DG_CONFIDENCE: case HID_DG_CONFIDENCE:
...@@ -73,16 +92,15 @@ static int egalax_input_mapping(struct hid_device *hdev, struct hid_input *hi, ...@@ -73,16 +92,15 @@ static int egalax_input_mapping(struct hid_device *hdev, struct hid_input *hi,
case HID_DG_CONTACTMAX: case HID_DG_CONTACTMAX:
return -1; return -1;
case HID_DG_CONTACTID: case HID_DG_CONTACTID:
hid_map_usage(hi, usage, bit, max, input_mt_init_slots(input, MAX_SLOTS);
EV_ABS, ABS_MT_TRACKING_ID);
return 1; return 1;
case HID_DG_TIPPRESSURE: case HID_DG_TIPPRESSURE:
field->logical_minimum = 0;
hid_map_usage(hi, usage, bit, max, hid_map_usage(hi, usage, bit, max,
EV_ABS, ABS_MT_PRESSURE); EV_ABS, ABS_MT_PRESSURE);
set_abs(input, ABS_MT_PRESSURE, field, SN_PRESSURE);
/* touchscreen emulation */ /* touchscreen emulation */
input_set_abs_params(hi->input, ABS_PRESSURE, set_abs(input, ABS_PRESSURE, field, SN_PRESSURE);
field->logical_minimum,
field->logical_maximum, 0, 0);
return 1; return 1;
} }
return 0; return 0;
...@@ -96,10 +114,10 @@ static int egalax_input_mapped(struct hid_device *hdev, struct hid_input *hi, ...@@ -96,10 +114,10 @@ static int egalax_input_mapped(struct hid_device *hdev, struct hid_input *hi,
struct hid_field *field, struct hid_usage *usage, struct hid_field *field, struct hid_usage *usage,
unsigned long **bit, int *max) unsigned long **bit, int *max)
{ {
/* tell hid-input to skip setup of these event types */
if (usage->type == EV_KEY || usage->type == EV_ABS) if (usage->type == EV_KEY || usage->type == EV_ABS)
clear_bit(usage->code, *bit); set_bit(usage->type, hi->input->evbit);
return -1;
return 0;
} }
/* /*
...@@ -108,58 +126,16 @@ static int egalax_input_mapped(struct hid_device *hdev, struct hid_input *hi, ...@@ -108,58 +126,16 @@ static int egalax_input_mapped(struct hid_device *hdev, struct hid_input *hi,
*/ */
static void egalax_filter_event(struct egalax_data *td, struct input_dev *input) static void egalax_filter_event(struct egalax_data *td, struct input_dev *input)
{ {
td->first = !td->first; /* touchscreen emulation */ input_mt_slot(input, td->slot);
input_mt_report_slot_state(input, MT_TOOL_FINGER, td->touch);
if (td->valid) { if (td->touch) {
/* emit multitouch events */ input_event(input, EV_ABS, ABS_MT_POSITION_X, td->x);
input_event(input, EV_ABS, ABS_MT_TRACKING_ID, td->id); input_event(input, EV_ABS, ABS_MT_POSITION_Y, td->y);
input_event(input, EV_ABS, ABS_MT_POSITION_X, td->x >> 3);
input_event(input, EV_ABS, ABS_MT_POSITION_Y, td->y >> 3);
input_event(input, EV_ABS, ABS_MT_PRESSURE, td->z); input_event(input, EV_ABS, ABS_MT_PRESSURE, td->z);
input_mt_sync(input);
/*
* touchscreen emulation: store (x, y) as
* the last valid values in this frame
*/
td->lastx = td->x;
td->lasty = td->y;
td->lastz = td->z;
}
/*
* touchscreen emulation: if this is the second finger and at least
* one in this frame is valid, the latest valid in the frame is
* the oldest on the panel, the one we want for single touch
*/
if (!td->first && td->activity) {
input_event(input, EV_ABS, ABS_X, td->lastx >> 3);
input_event(input, EV_ABS, ABS_Y, td->lasty >> 3);
input_event(input, EV_ABS, ABS_PRESSURE, td->lastz);
}
if (!td->valid) {
/*
* touchscreen emulation: if the first finger is invalid
* and there previously was finger activity, this is a release
*/
if (td->first && td->activity) {
input_event(input, EV_KEY, BTN_TOUCH, 0);
td->activity = false;
}
return;
}
/* touchscreen emulation: if no previous activity, emit touch event */
if (!td->activity) {
input_event(input, EV_KEY, BTN_TOUCH, 1);
td->activity = true;
} }
input_mt_report_pointer_emulation(input, true);
} }
static int egalax_event(struct hid_device *hid, struct hid_field *field, static int egalax_event(struct hid_device *hid, struct hid_field *field,
struct hid_usage *usage, __s32 value) struct hid_usage *usage, __s32 value)
{ {
...@@ -169,25 +145,26 @@ static int egalax_event(struct hid_device *hid, struct hid_field *field, ...@@ -169,25 +145,26 @@ static int egalax_event(struct hid_device *hid, struct hid_field *field,
* uses a standard parallel multitouch protocol (product ID == * uses a standard parallel multitouch protocol (product ID ==
* 48xx). The second is capacitive and uses an unusual "serial" * 48xx). The second is capacitive and uses an unusual "serial"
* protocol with a different message for each multitouch finger * protocol with a different message for each multitouch finger
* (product ID == 72xx). We do not yet generate a correct event * (product ID == 72xx).
* sequence for the capacitive/serial protocol.
*/ */
if (hid->claimed & HID_CLAIMED_INPUT) { if (hid->claimed & HID_CLAIMED_INPUT) {
struct input_dev *input = field->hidinput->input; struct input_dev *input = field->hidinput->input;
switch (usage->hid) { switch (usage->hid) {
case HID_DG_INRANGE: case HID_DG_INRANGE:
td->valid = value;
break;
case HID_DG_CONFIDENCE: case HID_DG_CONFIDENCE:
/* avoid interference from generic hidinput handling */ /* avoid interference from generic hidinput handling */
break; break;
case HID_DG_TIPSWITCH: case HID_DG_TIPSWITCH:
td->valid = value; td->touch = value;
break; break;
case HID_DG_TIPPRESSURE: case HID_DG_TIPPRESSURE:
td->z = value; td->z = value;
break; break;
case HID_DG_CONTACTID: case HID_DG_CONTACTID:
td->id = value; td->slot = clamp_val(value, 0, MAX_SLOTS - 1);
break; break;
case HID_GD_X: case HID_GD_X:
td->x = value; td->x = value;
...@@ -195,11 +172,11 @@ static int egalax_event(struct hid_device *hid, struct hid_field *field, ...@@ -195,11 +172,11 @@ static int egalax_event(struct hid_device *hid, struct hid_field *field,
case HID_GD_Y: case HID_GD_Y:
td->y = value; td->y = value;
/* this is the last field in a finger */ /* this is the last field in a finger */
egalax_filter_event(td, input); if (td->valid)
egalax_filter_event(td, input);
break; break;
case HID_DG_CONTACTCOUNT: case HID_DG_CONTACTCOUNT:
/* touch emulation: this is the last field in a frame */ /* touch emulation: this is the last field in a frame */
td->first = false;
break; break;
default: default:
...@@ -261,6 +238,12 @@ static const struct hid_device_id egalax_devices[] = { ...@@ -261,6 +238,12 @@ static const struct hid_device_id egalax_devices[] = {
USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH) }, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH) },
{ HID_USB_DEVICE(USB_VENDOR_ID_DWAV, { HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH1) }, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH1) },
{ HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH3) },
{ HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH4) },
{ } { }
}; };
MODULE_DEVICE_TABLE(hid, egalax_devices); MODULE_DEVICE_TABLE(hid, egalax_devices);
......
...@@ -196,6 +196,9 @@ ...@@ -196,6 +196,9 @@
#define USB_DEVICE_ID_EGALAX_TOUCHCONTROLLER 0x0001 #define USB_DEVICE_ID_EGALAX_TOUCHCONTROLLER 0x0001
#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH 0x480d #define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH 0x480d
#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH1 0x720c #define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH1 0x720c
#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH2 0x72a1
#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH3 0x480e
#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH4 0x726b
#define USB_VENDOR_ID_ELECOM 0x056e #define USB_VENDOR_ID_ELECOM 0x056e
#define USB_DEVICE_ID_ELECOM_BM084 0x0061 #define USB_DEVICE_ID_ELECOM_BM084 0x0061
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
# Each configuration option enables a list of files. # Each configuration option enables a list of files.
obj-$(CONFIG_INPUT) += input-core.o obj-$(CONFIG_INPUT) += input-core.o
input-core-objs := input.o input-compat.o ff-core.o input-core-y := input.o input-compat.o input-mt.o ff-core.o
obj-$(CONFIG_INPUT_FF_MEMLESS) += ff-memless.o obj-$(CONFIG_INPUT_FF_MEMLESS) += ff-memless.o
obj-$(CONFIG_INPUT_POLLDEV) += input-polldev.o obj-$(CONFIG_INPUT_POLLDEV) += input-polldev.o
......
...@@ -9,6 +9,8 @@ ...@@ -9,6 +9,8 @@
* *
*/ */
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/module.h> #include <linux/module.h>
#include <linux/input.h> #include <linux/input.h>
#include <linux/slab.h> #include <linux/slab.h>
...@@ -23,8 +25,7 @@ static void system_power_event(unsigned int keycode) ...@@ -23,8 +25,7 @@ static void system_power_event(unsigned int keycode)
switch (keycode) { switch (keycode) {
case KEY_SUSPEND: case KEY_SUSPEND:
apm_queue_event(APM_USER_SUSPEND); apm_queue_event(APM_USER_SUSPEND);
pr_info("Requesting system suspend...\n");
printk(KERN_INFO "apm-power: Requesting system suspend...\n");
break; break;
default: default:
break; break;
...@@ -65,18 +66,15 @@ static int apmpower_connect(struct input_handler *handler, ...@@ -65,18 +66,15 @@ static int apmpower_connect(struct input_handler *handler,
error = input_register_handle(handle); error = input_register_handle(handle);
if (error) { if (error) {
printk(KERN_ERR pr_err("Failed to register input power handler, error %d\n",
"apm-power: Failed to register input power handler, " error);
"error %d\n", error);
kfree(handle); kfree(handle);
return error; return error;
} }
error = input_open_device(handle); error = input_open_device(handle);
if (error) { if (error) {
printk(KERN_ERR pr_err("Failed to open input power device, error %d\n", error);
"apm-power: Failed to open input power device, "
"error %d\n", error);
input_unregister_handle(handle); input_unregister_handle(handle);
kfree(handle); kfree(handle);
return error; return error;
......
...@@ -26,6 +26,8 @@ ...@@ -26,6 +26,8 @@
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
*/ */
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/input.h> #include <linux/input.h>
...@@ -38,8 +40,8 @@ MODULE_LICENSE("GPL"); ...@@ -38,8 +40,8 @@ MODULE_LICENSE("GPL");
static void evbug_event(struct input_handle *handle, unsigned int type, unsigned int code, int value) static void evbug_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
{ {
printk(KERN_DEBUG "evbug.c: Event. Dev: %s, Type: %d, Code: %d, Value: %d\n", printk(KERN_DEBUG pr_fmt("Event. Dev: %s, Type: %d, Code: %d, Value: %d\n"),
dev_name(&handle->dev->dev), type, code, value); dev_name(&handle->dev->dev), type, code, value);
} }
static int evbug_connect(struct input_handler *handler, struct input_dev *dev, static int evbug_connect(struct input_handler *handler, struct input_dev *dev,
...@@ -64,10 +66,10 @@ static int evbug_connect(struct input_handler *handler, struct input_dev *dev, ...@@ -64,10 +66,10 @@ static int evbug_connect(struct input_handler *handler, struct input_dev *dev,
if (error) if (error)
goto err_unregister_handle; goto err_unregister_handle;
printk(KERN_DEBUG "evbug.c: Connected device: %s (%s at %s)\n", printk(KERN_DEBUG pr_fmt("Connected device: %s (%s at %s)\n"),
dev_name(&dev->dev), dev_name(&dev->dev),
dev->name ?: "unknown", dev->name ?: "unknown",
dev->phys ?: "unknown"); dev->phys ?: "unknown");
return 0; return 0;
...@@ -80,8 +82,8 @@ static int evbug_connect(struct input_handler *handler, struct input_dev *dev, ...@@ -80,8 +82,8 @@ static int evbug_connect(struct input_handler *handler, struct input_dev *dev,
static void evbug_disconnect(struct input_handle *handle) static void evbug_disconnect(struct input_handle *handle)
{ {
printk(KERN_DEBUG "evbug.c: Disconnected device: %s\n", printk(KERN_DEBUG pr_fmt("Disconnected device: %s\n"),
dev_name(&handle->dev->dev)); dev_name(&handle->dev->dev));
input_close_device(handle); input_close_device(handle);
input_unregister_handle(handle); input_unregister_handle(handle);
......
...@@ -8,6 +8,8 @@ ...@@ -8,6 +8,8 @@
* the Free Software Foundation. * the Free Software Foundation.
*/ */
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#define EVDEV_MINOR_BASE 64 #define EVDEV_MINOR_BASE 64
#define EVDEV_MINORS 32 #define EVDEV_MINORS 32
#define EVDEV_MIN_BUFFER_SIZE 64U #define EVDEV_MIN_BUFFER_SIZE 64U
...@@ -522,12 +524,11 @@ static int handle_eviocgbit(struct input_dev *dev, ...@@ -522,12 +524,11 @@ static int handle_eviocgbit(struct input_dev *dev,
if (type == EV_KEY && size == OLD_KEY_MAX) { if (type == EV_KEY && size == OLD_KEY_MAX) {
len = OLD_KEY_MAX; len = OLD_KEY_MAX;
if (printk_timed_ratelimit(&keymax_warn_time, 10 * 1000)) if (printk_timed_ratelimit(&keymax_warn_time, 10 * 1000))
printk(KERN_WARNING pr_warning("(EVIOCGBIT): Suspicious buffer size %u, "
"evdev.c(EVIOCGBIT): Suspicious buffer size %u, " "limiting output to %zu bytes. See "
"limiting output to %zu bytes. See " "http://userweb.kernel.org/~dtor/eviocgbit-bug.html\n",
"http://userweb.kernel.org/~dtor/eviocgbit-bug.html\n", OLD_KEY_MAX,
OLD_KEY_MAX, BITS_TO_LONGS(OLD_KEY_MAX) * sizeof(long));
BITS_TO_LONGS(OLD_KEY_MAX) * sizeof(long));
} }
return bits_to_user(bits, len, size, p, compat_mode); return bits_to_user(bits, len, size, p, compat_mode);
...@@ -686,6 +687,10 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd, ...@@ -686,6 +687,10 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd,
#define EVIOC_MASK_SIZE(nr) ((nr) & ~(_IOC_SIZEMASK << _IOC_SIZESHIFT)) #define EVIOC_MASK_SIZE(nr) ((nr) & ~(_IOC_SIZEMASK << _IOC_SIZESHIFT))
switch (EVIOC_MASK_SIZE(cmd)) { switch (EVIOC_MASK_SIZE(cmd)) {
case EVIOCGPROP(0):
return bits_to_user(dev->propbit, INPUT_PROP_MAX,
size, p, compat_mode);
case EVIOCGKEY(0): case EVIOCGKEY(0):
return bits_to_user(dev->key, KEY_MAX, size, p, compat_mode); return bits_to_user(dev->key, KEY_MAX, size, p, compat_mode);
...@@ -897,7 +902,7 @@ static int evdev_connect(struct input_handler *handler, struct input_dev *dev, ...@@ -897,7 +902,7 @@ static int evdev_connect(struct input_handler *handler, struct input_dev *dev,
break; break;
if (minor == EVDEV_MINORS) { if (minor == EVDEV_MINORS) {
printk(KERN_ERR "evdev: no more free evdev devices\n"); pr_err("no more free evdev devices\n");
return -ENFILE; return -ENFILE;
} }
......
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
/* #define DEBUG */ /* #define DEBUG */
#define debug(format, arg...) pr_debug("ff-core: " format "\n", ## arg) #define pr_fmt(fmt) KBUILD_BASENAME ": " fmt
#include <linux/input.h> #include <linux/input.h>
#include <linux/module.h> #include <linux/module.h>
...@@ -116,7 +116,7 @@ int input_ff_upload(struct input_dev *dev, struct ff_effect *effect, ...@@ -116,7 +116,7 @@ int input_ff_upload(struct input_dev *dev, struct ff_effect *effect,
if (effect->type < FF_EFFECT_MIN || effect->type > FF_EFFECT_MAX || if (effect->type < FF_EFFECT_MIN || effect->type > FF_EFFECT_MAX ||
!test_bit(effect->type, dev->ffbit)) { !test_bit(effect->type, dev->ffbit)) {
debug("invalid or not supported effect type in upload"); pr_debug("invalid or not supported effect type in upload\n");
return -EINVAL; return -EINVAL;
} }
...@@ -124,7 +124,7 @@ int input_ff_upload(struct input_dev *dev, struct ff_effect *effect, ...@@ -124,7 +124,7 @@ int input_ff_upload(struct input_dev *dev, struct ff_effect *effect,
(effect->u.periodic.waveform < FF_WAVEFORM_MIN || (effect->u.periodic.waveform < FF_WAVEFORM_MIN ||
effect->u.periodic.waveform > FF_WAVEFORM_MAX || effect->u.periodic.waveform > FF_WAVEFORM_MAX ||
!test_bit(effect->u.periodic.waveform, dev->ffbit))) { !test_bit(effect->u.periodic.waveform, dev->ffbit))) {
debug("invalid or not supported wave form in upload"); pr_debug("invalid or not supported wave form in upload\n");
return -EINVAL; return -EINVAL;
} }
...@@ -246,7 +246,7 @@ static int flush_effects(struct input_dev *dev, struct file *file) ...@@ -246,7 +246,7 @@ static int flush_effects(struct input_dev *dev, struct file *file)
struct ff_device *ff = dev->ff; struct ff_device *ff = dev->ff;
int i; int i;
debug("flushing now"); pr_debug("flushing now\n");
mutex_lock(&ff->mutex); mutex_lock(&ff->mutex);
...@@ -315,8 +315,7 @@ int input_ff_create(struct input_dev *dev, int max_effects) ...@@ -315,8 +315,7 @@ int input_ff_create(struct input_dev *dev, int max_effects)
int i; int i;
if (!max_effects) { if (!max_effects) {
printk(KERN_ERR pr_err("cannot allocate device without any effects\n");
"ff-core: cannot allocate device without any effects\n");
return -EINVAL; return -EINVAL;
} }
......
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
/* #define DEBUG */ /* #define DEBUG */
#define debug(format, arg...) pr_debug("ff-memless: " format "\n", ## arg) #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/input.h> #include <linux/input.h>
...@@ -129,7 +129,7 @@ static void ml_schedule_timer(struct ml_device *ml) ...@@ -129,7 +129,7 @@ static void ml_schedule_timer(struct ml_device *ml)
int events = 0; int events = 0;
int i; int i;
debug("calculating next timer"); pr_debug("calculating next timer\n");
for (i = 0; i < FF_MEMLESS_EFFECTS; i++) { for (i = 0; i < FF_MEMLESS_EFFECTS; i++) {
...@@ -149,10 +149,10 @@ static void ml_schedule_timer(struct ml_device *ml) ...@@ -149,10 +149,10 @@ static void ml_schedule_timer(struct ml_device *ml)
} }
if (!events) { if (!events) {
debug("no actions"); pr_debug("no actions\n");
del_timer(&ml->timer); del_timer(&ml->timer);
} else { } else {
debug("timer set"); pr_debug("timer set\n");
mod_timer(&ml->timer, earliest); mod_timer(&ml->timer, earliest);
} }
} }
...@@ -173,8 +173,8 @@ static int apply_envelope(struct ml_effect_state *state, int value, ...@@ -173,8 +173,8 @@ static int apply_envelope(struct ml_effect_state *state, int value,
if (envelope->attack_length && if (envelope->attack_length &&
time_before(now, time_before(now,
state->play_at + msecs_to_jiffies(envelope->attack_length))) { state->play_at + msecs_to_jiffies(envelope->attack_length))) {
debug("value = 0x%x, attack_level = 0x%x", value, pr_debug("value = 0x%x, attack_level = 0x%x\n",
envelope->attack_level); value, envelope->attack_level);
time_from_level = jiffies_to_msecs(now - state->play_at); time_from_level = jiffies_to_msecs(now - state->play_at);
time_of_envelope = envelope->attack_length; time_of_envelope = envelope->attack_length;
envelope_level = min_t(__s16, envelope->attack_level, 0x7fff); envelope_level = min_t(__s16, envelope->attack_level, 0x7fff);
...@@ -191,13 +191,13 @@ static int apply_envelope(struct ml_effect_state *state, int value, ...@@ -191,13 +191,13 @@ static int apply_envelope(struct ml_effect_state *state, int value,
difference = abs(value) - envelope_level; difference = abs(value) - envelope_level;
debug("difference = %d", difference); pr_debug("difference = %d\n", difference);
debug("time_from_level = 0x%x", time_from_level); pr_debug("time_from_level = 0x%x\n", time_from_level);
debug("time_of_envelope = 0x%x", time_of_envelope); pr_debug("time_of_envelope = 0x%x\n", time_of_envelope);
difference = difference * time_from_level / time_of_envelope; difference = difference * time_from_level / time_of_envelope;
debug("difference = %d", difference); pr_debug("difference = %d\n", difference);
return value < 0 ? return value < 0 ?
-(difference + envelope_level) : (difference + envelope_level); -(difference + envelope_level) : (difference + envelope_level);
...@@ -215,8 +215,7 @@ static int get_compatible_type(struct ff_device *ff, int effect_type) ...@@ -215,8 +215,7 @@ static int get_compatible_type(struct ff_device *ff, int effect_type)
if (effect_type == FF_PERIODIC && test_bit(FF_RUMBLE, ff->ffbit)) if (effect_type == FF_PERIODIC && test_bit(FF_RUMBLE, ff->ffbit))
return FF_RUMBLE; return FF_RUMBLE;
printk(KERN_ERR pr_err("invalid type in get_compatible_type()\n");
"ff-memless: invalid type in get_compatible_type()\n");
return 0; return 0;
} }
...@@ -312,7 +311,7 @@ static void ml_combine_effects(struct ff_effect *effect, ...@@ -312,7 +311,7 @@ static void ml_combine_effects(struct ff_effect *effect,
break; break;
default: default:
printk(KERN_ERR "ff-memless: invalid type in ml_combine_effects()\n"); pr_err("invalid type in ml_combine_effects()\n");
break; break;
} }
...@@ -406,7 +405,7 @@ static void ml_effect_timer(unsigned long timer_data) ...@@ -406,7 +405,7 @@ static void ml_effect_timer(unsigned long timer_data)
struct ml_device *ml = dev->ff->private; struct ml_device *ml = dev->ff->private;
unsigned long flags; unsigned long flags;
debug("timer: updating effects"); pr_debug("timer: updating effects\n");
spin_lock_irqsave(&dev->event_lock, flags); spin_lock_irqsave(&dev->event_lock, flags);
ml_play_effects(ml); ml_play_effects(ml);
...@@ -438,7 +437,7 @@ static int ml_ff_playback(struct input_dev *dev, int effect_id, int value) ...@@ -438,7 +437,7 @@ static int ml_ff_playback(struct input_dev *dev, int effect_id, int value)
struct ml_effect_state *state = &ml->states[effect_id]; struct ml_effect_state *state = &ml->states[effect_id];
if (value > 0) { if (value > 0) {
debug("initiated play"); pr_debug("initiated play\n");
__set_bit(FF_EFFECT_STARTED, &state->flags); __set_bit(FF_EFFECT_STARTED, &state->flags);
state->count = value; state->count = value;
...@@ -449,7 +448,7 @@ static int ml_ff_playback(struct input_dev *dev, int effect_id, int value) ...@@ -449,7 +448,7 @@ static int ml_ff_playback(struct input_dev *dev, int effect_id, int value)
state->adj_at = state->play_at; state->adj_at = state->play_at;
} else { } else {
debug("initiated stop"); pr_debug("initiated stop\n");
if (test_bit(FF_EFFECT_PLAYING, &state->flags)) if (test_bit(FF_EFFECT_PLAYING, &state->flags))
__set_bit(FF_EFFECT_ABORTING, &state->flags); __set_bit(FF_EFFECT_ABORTING, &state->flags);
......
...@@ -18,13 +18,11 @@ ...@@ -18,13 +18,11 @@
#include <linux/ioport.h> #include <linux/ioport.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/gameport.h> #include <linux/gameport.h>
#include <linux/wait.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/kthread.h> #include <linux/workqueue.h>
#include <linux/sched.h> /* HZ */ #include <linux/sched.h> /* HZ */
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/freezer.h>
/*#include <asm/io.h>*/ /*#include <asm/io.h>*/
...@@ -234,58 +232,22 @@ struct gameport_event { ...@@ -234,58 +232,22 @@ struct gameport_event {
static DEFINE_SPINLOCK(gameport_event_lock); /* protects gameport_event_list */ static DEFINE_SPINLOCK(gameport_event_lock); /* protects gameport_event_list */
static LIST_HEAD(gameport_event_list); static LIST_HEAD(gameport_event_list);
static DECLARE_WAIT_QUEUE_HEAD(gameport_wait);
static struct task_struct *gameport_task;
static int gameport_queue_event(void *object, struct module *owner, static struct gameport_event *gameport_get_event(void)
enum gameport_event_type event_type)
{ {
struct gameport_event *event = NULL;
unsigned long flags; unsigned long flags;
struct gameport_event *event;
int retval = 0;
spin_lock_irqsave(&gameport_event_lock, flags); spin_lock_irqsave(&gameport_event_lock, flags);
/* if (!list_empty(&gameport_event_list)) {
* Scan event list for the other events for the same gameport port, event = list_first_entry(&gameport_event_list,
* starting with the most recent one. If event is the same we struct gameport_event, node);
* do not need add new one. If event is of different type we list_del_init(&event->node);
* need to add this event and should not look further because
* we need to preseve sequence of distinct events.
*/
list_for_each_entry_reverse(event, &gameport_event_list, node) {
if (event->object == object) {
if (event->type == event_type)
goto out;
break;
}
}
event = kmalloc(sizeof(struct gameport_event), GFP_ATOMIC);
if (!event) {
pr_err("Not enough memory to queue event %d\n", event_type);
retval = -ENOMEM;
goto out;
}
if (!try_module_get(owner)) {
pr_warning("Can't get module reference, dropping event %d\n",
event_type);
kfree(event);
retval = -EINVAL;
goto out;
} }
event->type = event_type;
event->object = object;
event->owner = owner;
list_add_tail(&event->node, &gameport_event_list);
wake_up(&gameport_wait);
out:
spin_unlock_irqrestore(&gameport_event_lock, flags); spin_unlock_irqrestore(&gameport_event_lock, flags);
return retval; return event;
} }
static void gameport_free_event(struct gameport_event *event) static void gameport_free_event(struct gameport_event *event)
...@@ -319,24 +281,8 @@ static void gameport_remove_duplicate_events(struct gameport_event *event) ...@@ -319,24 +281,8 @@ static void gameport_remove_duplicate_events(struct gameport_event *event)
spin_unlock_irqrestore(&gameport_event_lock, flags); spin_unlock_irqrestore(&gameport_event_lock, flags);
} }
static struct gameport_event *gameport_get_event(void)
{
struct gameport_event *event = NULL;
unsigned long flags;
spin_lock_irqsave(&gameport_event_lock, flags);
if (!list_empty(&gameport_event_list)) {
event = list_first_entry(&gameport_event_list,
struct gameport_event, node);
list_del_init(&event->node);
}
spin_unlock_irqrestore(&gameport_event_lock, flags);
return event;
}
static void gameport_handle_event(void) static void gameport_handle_events(struct work_struct *work)
{ {
struct gameport_event *event; struct gameport_event *event;
...@@ -368,6 +314,59 @@ static void gameport_handle_event(void) ...@@ -368,6 +314,59 @@ static void gameport_handle_event(void)
mutex_unlock(&gameport_mutex); mutex_unlock(&gameport_mutex);
} }
static DECLARE_WORK(gameport_event_work, gameport_handle_events);
static int gameport_queue_event(void *object, struct module *owner,
enum gameport_event_type event_type)
{
unsigned long flags;
struct gameport_event *event;
int retval = 0;
spin_lock_irqsave(&gameport_event_lock, flags);
/*
* Scan event list for the other events for the same gameport port,
* starting with the most recent one. If event is the same we
* do not need add new one. If event is of different type we
* need to add this event and should not look further because
* we need to preserve sequence of distinct events.
*/
list_for_each_entry_reverse(event, &gameport_event_list, node) {
if (event->object == object) {
if (event->type == event_type)
goto out;
break;
}
}
event = kmalloc(sizeof(struct gameport_event), GFP_ATOMIC);
if (!event) {
pr_err("Not enough memory to queue event %d\n", event_type);
retval = -ENOMEM;
goto out;
}
if (!try_module_get(owner)) {
pr_warning("Can't get module reference, dropping event %d\n",
event_type);
kfree(event);
retval = -EINVAL;
goto out;
}
event->type = event_type;
event->object = object;
event->owner = owner;
list_add_tail(&event->node, &gameport_event_list);
schedule_work(&gameport_event_work);
out:
spin_unlock_irqrestore(&gameport_event_lock, flags);
return retval;
}
/* /*
* Remove all events that have been submitted for a given object, * Remove all events that have been submitted for a given object,
* be it a gameport port or a driver. * be it a gameport port or a driver.
...@@ -419,19 +418,6 @@ static struct gameport *gameport_get_pending_child(struct gameport *parent) ...@@ -419,19 +418,6 @@ static struct gameport *gameport_get_pending_child(struct gameport *parent)
return child; return child;
} }
static int gameport_thread(void *nothing)
{
set_freezable();
do {
gameport_handle_event();
wait_event_freezable(gameport_wait,
kthread_should_stop() || !list_empty(&gameport_event_list));
} while (!kthread_should_stop());
return 0;
}
/* /*
* Gameport port operations * Gameport port operations
*/ */
...@@ -814,13 +800,6 @@ static int __init gameport_init(void) ...@@ -814,13 +800,6 @@ static int __init gameport_init(void)
return error; return error;
} }
gameport_task = kthread_run(gameport_thread, NULL, "kgameportd");
if (IS_ERR(gameport_task)) {
bus_unregister(&gameport_bus);
error = PTR_ERR(gameport_task);
pr_err("Failed to start kgameportd, error: %d\n", error);
return error;
}
return 0; return 0;
} }
...@@ -828,7 +807,12 @@ static int __init gameport_init(void) ...@@ -828,7 +807,12 @@ static int __init gameport_init(void)
static void __exit gameport_exit(void) static void __exit gameport_exit(void)
{ {
bus_unregister(&gameport_bus); bus_unregister(&gameport_bus);
kthread_stop(gameport_task);
/*
* There should not be any outstanding events but work may
* still be scheduled so simply cancel it.
*/
cancel_work_sync(&gameport_event_work);
} }
subsys_initcall(gameport_init); subsys_initcall(gameport_init);
......
/*
* Input Multitouch Library
*
* Copyright (c) 2008-2010 Henrik Rydberg
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*/
#include <linux/input/mt.h>
#include <linux/slab.h>
#define TRKID_SGN ((TRKID_MAX + 1) >> 1)
/**
* input_mt_init_slots() - initialize MT input slots
* @dev: input device supporting MT events and finger tracking
* @num_slots: number of slots used by the device
*
* This function allocates all necessary memory for MT slot handling
* in the input device, prepares the ABS_MT_SLOT and
* ABS_MT_TRACKING_ID events for use and sets up appropriate buffers.
* May be called repeatedly. Returns -EINVAL if attempting to
* reinitialize with a different number of slots.
*/
int input_mt_init_slots(struct input_dev *dev, unsigned int num_slots)
{
int i;
if (!num_slots)
return 0;
if (dev->mt)
return dev->mtsize != num_slots ? -EINVAL : 0;
dev->mt = kcalloc(num_slots, sizeof(struct input_mt_slot), GFP_KERNEL);
if (!dev->mt)
return -ENOMEM;
dev->mtsize = num_slots;
input_set_abs_params(dev, ABS_MT_SLOT, 0, num_slots - 1, 0, 0);
input_set_abs_params(dev, ABS_MT_TRACKING_ID, 0, TRKID_MAX, 0, 0);
input_set_events_per_packet(dev, 6 * num_slots);
/* Mark slots as 'unused' */
for (i = 0; i < num_slots; i++)
input_mt_set_value(&dev->mt[i], ABS_MT_TRACKING_ID, -1);
return 0;
}
EXPORT_SYMBOL(input_mt_init_slots);
/**
* input_mt_destroy_slots() - frees the MT slots of the input device
* @dev: input device with allocated MT slots
*
* This function is only needed in error path as the input core will
* automatically free the MT slots when the device is destroyed.
*/
void input_mt_destroy_slots(struct input_dev *dev)
{
kfree(dev->mt);
dev->mt = NULL;
dev->mtsize = 0;
dev->slot = 0;
dev->trkid = 0;
}
EXPORT_SYMBOL(input_mt_destroy_slots);
/**
* input_mt_report_slot_state() - report contact state
* @dev: input device with allocated MT slots
* @tool_type: the tool type to use in this slot
* @active: true if contact is active, false otherwise
*
* Reports a contact via ABS_MT_TRACKING_ID, and optionally
* ABS_MT_TOOL_TYPE. If active is true and the slot is currently
* inactive, or if the tool type is changed, a new tracking id is
* assigned to the slot. The tool type is only reported if the
* corresponding absbit field is set.
*/
void input_mt_report_slot_state(struct input_dev *dev,
unsigned int tool_type, bool active)
{
struct input_mt_slot *mt;
int id;
if (!dev->mt || !active) {
input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, -1);
return;
}
mt = &dev->mt[dev->slot];
id = input_mt_get_value(mt, ABS_MT_TRACKING_ID);
if (id < 0 || input_mt_get_value(mt, ABS_MT_TOOL_TYPE) != tool_type)
id = input_mt_new_trkid(dev);
input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, id);
input_event(dev, EV_ABS, ABS_MT_TOOL_TYPE, tool_type);
}
EXPORT_SYMBOL(input_mt_report_slot_state);
/**
* input_mt_report_finger_count() - report contact count
* @dev: input device with allocated MT slots
* @count: the number of contacts
*
* Reports the contact count via BTN_TOOL_FINGER, BTN_TOOL_DOUBLETAP,
* BTN_TOOL_TRIPLETAP and BTN_TOOL_QUADTAP.
*
* The input core ensures only the KEY events already setup for
* this device will produce output.
*/
void input_mt_report_finger_count(struct input_dev *dev, int count)
{
input_event(dev, EV_KEY, BTN_TOOL_FINGER, count == 1);
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);
}
EXPORT_SYMBOL(input_mt_report_finger_count);
/**
* input_mt_report_pointer_emulation() - common pointer emulation
* @dev: input device with allocated MT slots
* @use_count: report number of active contacts as finger count
*
* Performs legacy pointer emulation via BTN_TOUCH, ABS_X, ABS_Y and
* ABS_PRESSURE. Touchpad finger count is emulated if use_count is true.
*
* The input core ensures only the KEY and ABS axes already setup for
* this device will produce output.
*/
void input_mt_report_pointer_emulation(struct input_dev *dev, bool use_count)
{
struct input_mt_slot *oldest = 0;
int oldid = dev->trkid;
int count = 0;
int i;
for (i = 0; i < dev->mtsize; ++i) {
struct input_mt_slot *ps = &dev->mt[i];
int id = input_mt_get_value(ps, ABS_MT_TRACKING_ID);
if (id < 0)
continue;
if ((id - oldid) & TRKID_SGN) {
oldest = ps;
oldid = id;
}
count++;
}
input_event(dev, EV_KEY, BTN_TOUCH, count > 0);
if (use_count)
input_mt_report_finger_count(dev, count);
if (oldest) {
int x = input_mt_get_value(oldest, ABS_MT_POSITION_X);
int y = input_mt_get_value(oldest, ABS_MT_POSITION_Y);
int p = input_mt_get_value(oldest, ABS_MT_PRESSURE);
input_event(dev, EV_ABS, ABS_X, x);
input_event(dev, EV_ABS, ABS_Y, y);
input_event(dev, EV_ABS, ABS_PRESSURE, p);
} else {
input_event(dev, EV_ABS, ABS_PRESSURE, 0);
}
}
EXPORT_SYMBOL(input_mt_report_pointer_emulation);
...@@ -8,6 +8,8 @@ ...@@ -8,6 +8,8 @@
* the Free Software Foundation. * the Free Software Foundation.
*/ */
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/jiffies.h> #include <linux/jiffies.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/mutex.h> #include <linux/mutex.h>
...@@ -33,8 +35,7 @@ static int input_polldev_start_workqueue(void) ...@@ -33,8 +35,7 @@ static int input_polldev_start_workqueue(void)
if (!polldev_users) { if (!polldev_users) {
polldev_wq = create_singlethread_workqueue("ipolldevd"); polldev_wq = create_singlethread_workqueue("ipolldevd");
if (!polldev_wq) { if (!polldev_wq) {
printk(KERN_ERR "input-polldev: failed to create " pr_err("failed to create ipolldevd workqueue\n");
"ipolldevd workqueue\n");
retval = -ENOMEM; retval = -ENOMEM;
goto out; goto out;
} }
......
...@@ -10,9 +10,11 @@ ...@@ -10,9 +10,11 @@
* the Free Software Foundation. * the Free Software Foundation.
*/ */
#define pr_fmt(fmt) KBUILD_BASENAME ": " fmt
#include <linux/init.h> #include <linux/init.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/input.h> #include <linux/input/mt.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/random.h> #include <linux/random.h>
...@@ -959,10 +961,8 @@ static int input_attach_handler(struct input_dev *dev, struct input_handler *han ...@@ -959,10 +961,8 @@ static int input_attach_handler(struct input_dev *dev, struct input_handler *han
error = handler->connect(handler, dev, id); error = handler->connect(handler, dev, id);
if (error && error != -ENODEV) if (error && error != -ENODEV)
printk(KERN_ERR pr_err("failed to attach handler %s to device %s, error: %d\n",
"input: failed to attach handler %s to device %s, " handler->name, kobject_name(&dev->dev.kobj), error);
"error: %d\n",
handler->name, kobject_name(&dev->dev.kobj), error);
return error; return error;
} }
...@@ -1110,6 +1110,8 @@ static int input_devices_seq_show(struct seq_file *seq, void *v) ...@@ -1110,6 +1110,8 @@ static int input_devices_seq_show(struct seq_file *seq, void *v)
seq_printf(seq, "%s ", handle->name); seq_printf(seq, "%s ", handle->name);
seq_putc(seq, '\n'); seq_putc(seq, '\n');
input_seq_print_bitmap(seq, "PROP", dev->propbit, INPUT_PROP_MAX);
input_seq_print_bitmap(seq, "EV", dev->evbit, EV_MAX); input_seq_print_bitmap(seq, "EV", dev->evbit, EV_MAX);
if (test_bit(EV_KEY, dev->evbit)) if (test_bit(EV_KEY, dev->evbit))
input_seq_print_bitmap(seq, "KEY", dev->keybit, KEY_MAX); input_seq_print_bitmap(seq, "KEY", dev->keybit, KEY_MAX);
...@@ -1333,11 +1335,26 @@ static ssize_t input_dev_show_modalias(struct device *dev, ...@@ -1333,11 +1335,26 @@ static ssize_t input_dev_show_modalias(struct device *dev,
} }
static DEVICE_ATTR(modalias, S_IRUGO, input_dev_show_modalias, NULL); static DEVICE_ATTR(modalias, S_IRUGO, input_dev_show_modalias, NULL);
static int input_print_bitmap(char *buf, int buf_size, unsigned long *bitmap,
int max, int add_cr);
static ssize_t input_dev_show_properties(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct input_dev *input_dev = to_input_dev(dev);
int len = input_print_bitmap(buf, PAGE_SIZE, input_dev->propbit,
INPUT_PROP_MAX, true);
return min_t(int, len, PAGE_SIZE);
}
static DEVICE_ATTR(properties, S_IRUGO, input_dev_show_properties, NULL);
static struct attribute *input_dev_attrs[] = { static struct attribute *input_dev_attrs[] = {
&dev_attr_name.attr, &dev_attr_name.attr,
&dev_attr_phys.attr, &dev_attr_phys.attr,
&dev_attr_uniq.attr, &dev_attr_uniq.attr,
&dev_attr_modalias.attr, &dev_attr_modalias.attr,
&dev_attr_properties.attr,
NULL NULL
}; };
...@@ -1471,7 +1488,7 @@ static int input_add_uevent_bm_var(struct kobj_uevent_env *env, ...@@ -1471,7 +1488,7 @@ static int input_add_uevent_bm_var(struct kobj_uevent_env *env,
{ {
int len; int len;
if (add_uevent_var(env, "%s=", name)) if (add_uevent_var(env, "%s", name))
return -ENOMEM; return -ENOMEM;
len = input_print_bitmap(&env->buf[env->buflen - 1], len = input_print_bitmap(&env->buf[env->buflen - 1],
...@@ -1537,6 +1554,8 @@ static int input_dev_uevent(struct device *device, struct kobj_uevent_env *env) ...@@ -1537,6 +1554,8 @@ static int input_dev_uevent(struct device *device, struct kobj_uevent_env *env)
if (dev->uniq) if (dev->uniq)
INPUT_ADD_HOTPLUG_VAR("UNIQ=\"%s\"", dev->uniq); INPUT_ADD_HOTPLUG_VAR("UNIQ=\"%s\"", dev->uniq);
INPUT_ADD_HOTPLUG_BM_VAR("PROP=", dev->propbit, INPUT_PROP_MAX);
INPUT_ADD_HOTPLUG_BM_VAR("EV=", dev->evbit, EV_MAX); INPUT_ADD_HOTPLUG_BM_VAR("EV=", dev->evbit, EV_MAX);
if (test_bit(EV_KEY, dev->evbit)) if (test_bit(EV_KEY, dev->evbit))
INPUT_ADD_HOTPLUG_BM_VAR("KEY=", dev->keybit, KEY_MAX); INPUT_ADD_HOTPLUG_BM_VAR("KEY=", dev->keybit, KEY_MAX);
...@@ -1725,52 +1744,6 @@ void input_free_device(struct input_dev *dev) ...@@ -1725,52 +1744,6 @@ void input_free_device(struct input_dev *dev)
} }
EXPORT_SYMBOL(input_free_device); EXPORT_SYMBOL(input_free_device);
/**
* input_mt_create_slots() - create MT input slots
* @dev: input device supporting MT events and finger tracking
* @num_slots: number of slots used by the device
*
* This function allocates all necessary memory for MT slot handling in the
* input device, and adds ABS_MT_SLOT to the device capabilities. All slots
* are initially marked as unused by setting ABS_MT_TRACKING_ID to -1.
*/
int input_mt_create_slots(struct input_dev *dev, unsigned int num_slots)
{
int i;
if (!num_slots)
return 0;
dev->mt = kcalloc(num_slots, sizeof(struct input_mt_slot), GFP_KERNEL);
if (!dev->mt)
return -ENOMEM;
dev->mtsize = num_slots;
input_set_abs_params(dev, ABS_MT_SLOT, 0, num_slots - 1, 0, 0);
/* Mark slots as 'unused' */
for (i = 0; i < num_slots; i++)
dev->mt[i].abs[ABS_MT_TRACKING_ID - ABS_MT_FIRST] = -1;
return 0;
}
EXPORT_SYMBOL(input_mt_create_slots);
/**
* input_mt_destroy_slots() - frees the MT slots of the input device
* @dev: input device with allocated MT slots
*
* This function is only needed in error path as the input core will
* automatically free the MT slots when the device is destroyed.
*/
void input_mt_destroy_slots(struct input_dev *dev)
{
kfree(dev->mt);
dev->mt = NULL;
dev->mtsize = 0;
}
EXPORT_SYMBOL(input_mt_destroy_slots);
/** /**
* input_set_capability - mark device as capable of a certain event * input_set_capability - mark device as capable of a certain event
* @dev: device that is capable of emitting or accepting event * @dev: device that is capable of emitting or accepting event
...@@ -1820,9 +1793,8 @@ void input_set_capability(struct input_dev *dev, unsigned int type, unsigned int ...@@ -1820,9 +1793,8 @@ void input_set_capability(struct input_dev *dev, unsigned int type, unsigned int
break; break;
default: default:
printk(KERN_ERR pr_err("input_set_capability: unknown type %u (code %u)\n",
"input_set_capability: unknown type %u (code %u)\n", type, code);
type, code);
dump_stack(); dump_stack();
return; return;
} }
...@@ -1904,8 +1876,9 @@ int input_register_device(struct input_dev *dev) ...@@ -1904,8 +1876,9 @@ int input_register_device(struct input_dev *dev)
return error; return error;
path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL); path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL);
printk(KERN_INFO "input: %s as %s\n", pr_info("%s as %s\n",
dev->name ? dev->name : "Unspecified device", path ? path : "N/A"); dev->name ? dev->name : "Unspecified device",
path ? path : "N/A");
kfree(path); kfree(path);
error = mutex_lock_interruptible(&input_mutex); error = mutex_lock_interruptible(&input_mutex);
...@@ -2187,7 +2160,7 @@ static int __init input_init(void) ...@@ -2187,7 +2160,7 @@ static int __init input_init(void)
err = class_register(&input_class); err = class_register(&input_class);
if (err) { if (err) {
printk(KERN_ERR "input: unable to register input_dev class\n"); pr_err("unable to register input_dev class\n");
return err; return err;
} }
...@@ -2197,7 +2170,7 @@ static int __init input_init(void) ...@@ -2197,7 +2170,7 @@ static int __init input_init(void)
err = register_chrdev(INPUT_MAJOR, "input", &input_fops); err = register_chrdev(INPUT_MAJOR, "input", &input_fops);
if (err) { if (err) {
printk(KERN_ERR "input: unable to register char major %d", INPUT_MAJOR); pr_err("unable to register char major %d", INPUT_MAJOR);
goto fail2; goto fail2;
} }
......
...@@ -10,6 +10,8 @@ ...@@ -10,6 +10,8 @@
* (at your option) any later version. * (at your option) any later version.
*/ */
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <asm/io.h> #include <asm/io.h>
#include <asm/system.h> #include <asm/system.h>
#include <linux/delay.h> #include <linux/delay.h>
...@@ -806,7 +808,7 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev, ...@@ -806,7 +808,7 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev,
break; break;
if (minor == JOYDEV_MINORS) { if (minor == JOYDEV_MINORS) {
printk(KERN_ERR "joydev: no more free joydev devices\n"); pr_err("no more free joydev devices\n");
return -ENFILE; return -ENFILE;
} }
......
...@@ -4,17 +4,8 @@ ...@@ -4,17 +4,8 @@
# By Johann Deneux <johann.deneux@gmail.com> # By Johann Deneux <johann.deneux@gmail.com>
# #
# Goal definition
iforce-objs := iforce-ff.o iforce-main.o iforce-packets.o
obj-$(CONFIG_JOYSTICK_IFORCE) += iforce.o obj-$(CONFIG_JOYSTICK_IFORCE) += iforce.o
ifeq ($(CONFIG_JOYSTICK_IFORCE_232),y) iforce-y := iforce-ff.o iforce-main.o iforce-packets.o
iforce-objs += iforce-serio.o iforce-$(CONFIG_JOYSTICK_IFORCE_232) += iforce-serio.o
endif iforce-$(CONFIG_JOYSTICK_IFORCE_USB) += iforce-usb.o
ifeq ($(CONFIG_JOYSTICK_IFORCE_USB),y)
iforce-objs += iforce-usb.o
endif
EXTRA_CFLAGS = -Werror-implicit-function-declaration
...@@ -543,21 +543,25 @@ static void xpad_irq_out(struct urb *urb) ...@@ -543,21 +543,25 @@ static void xpad_irq_out(struct urb *urb)
static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad) static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad)
{ {
struct usb_endpoint_descriptor *ep_irq_out; struct usb_endpoint_descriptor *ep_irq_out;
int error = -ENOMEM; int error;
if (xpad->xtype != XTYPE_XBOX360 && xpad->xtype != XTYPE_XBOX) if (xpad->xtype != XTYPE_XBOX360 && xpad->xtype != XTYPE_XBOX)
return 0; return 0;
xpad->odata = usb_alloc_coherent(xpad->udev, XPAD_PKT_LEN, xpad->odata = usb_alloc_coherent(xpad->udev, XPAD_PKT_LEN,
GFP_KERNEL, &xpad->odata_dma); GFP_KERNEL, &xpad->odata_dma);
if (!xpad->odata) if (!xpad->odata) {
error = -ENOMEM;
goto fail1; goto fail1;
}
mutex_init(&xpad->odata_mutex); mutex_init(&xpad->odata_mutex);
xpad->irq_out = usb_alloc_urb(0, GFP_KERNEL); xpad->irq_out = usb_alloc_urb(0, GFP_KERNEL);
if (!xpad->irq_out) if (!xpad->irq_out) {
error = -ENOMEM;
goto fail2; goto fail2;
}
ep_irq_out = &intf->cur_altsetting->endpoint[1].desc; ep_irq_out = &intf->cur_altsetting->endpoint[1].desc;
usb_fill_int_urb(xpad->irq_out, xpad->udev, usb_fill_int_urb(xpad->irq_out, xpad->udev,
...@@ -728,7 +732,7 @@ static void xpad_led_disconnect(struct usb_xpad *xpad) ...@@ -728,7 +732,7 @@ static void xpad_led_disconnect(struct usb_xpad *xpad)
if (xpad_led) { if (xpad_led) {
led_classdev_unregister(&xpad_led->led_cdev); led_classdev_unregister(&xpad_led->led_cdev);
kfree(xpad_led->name); kfree(xpad_led);
} }
} }
#else #else
...@@ -756,8 +760,9 @@ static void xpad_close(struct input_dev *dev) ...@@ -756,8 +760,9 @@ static void xpad_close(struct input_dev *dev)
{ {
struct usb_xpad *xpad = input_get_drvdata(dev); struct usb_xpad *xpad = input_get_drvdata(dev);
if(xpad->xtype != XTYPE_XBOX360W) if (xpad->xtype != XTYPE_XBOX360W)
usb_kill_urb(xpad->irq_in); usb_kill_urb(xpad->irq_in);
xpad_stop_output(xpad); xpad_stop_output(xpad);
} }
...@@ -789,8 +794,7 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id ...@@ -789,8 +794,7 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
struct usb_xpad *xpad; struct usb_xpad *xpad;
struct input_dev *input_dev; struct input_dev *input_dev;
struct usb_endpoint_descriptor *ep_irq_in; struct usb_endpoint_descriptor *ep_irq_in;
int i; int i, error;
int error = -ENOMEM;
for (i = 0; xpad_device[i].idVendor; i++) { for (i = 0; xpad_device[i].idVendor; i++) {
if ((le16_to_cpu(udev->descriptor.idVendor) == xpad_device[i].idVendor) && if ((le16_to_cpu(udev->descriptor.idVendor) == xpad_device[i].idVendor) &&
...@@ -800,17 +804,23 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id ...@@ -800,17 +804,23 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
xpad = kzalloc(sizeof(struct usb_xpad), GFP_KERNEL); xpad = kzalloc(sizeof(struct usb_xpad), GFP_KERNEL);
input_dev = input_allocate_device(); input_dev = input_allocate_device();
if (!xpad || !input_dev) if (!xpad || !input_dev) {
error = -ENOMEM;
goto fail1; goto fail1;
}
xpad->idata = usb_alloc_coherent(udev, XPAD_PKT_LEN, xpad->idata = usb_alloc_coherent(udev, XPAD_PKT_LEN,
GFP_KERNEL, &xpad->idata_dma); GFP_KERNEL, &xpad->idata_dma);
if (!xpad->idata) if (!xpad->idata) {
error = -ENOMEM;
goto fail1; goto fail1;
}
xpad->irq_in = usb_alloc_urb(0, GFP_KERNEL); xpad->irq_in = usb_alloc_urb(0, GFP_KERNEL);
if (!xpad->irq_in) if (!xpad->irq_in) {
error = -ENOMEM;
goto fail2; goto fail2;
}
xpad->udev = udev; xpad->udev = udev;
xpad->mapping = xpad_device[i].mapping; xpad->mapping = xpad_device[i].mapping;
...@@ -887,15 +897,15 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id ...@@ -887,15 +897,15 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
error = xpad_init_output(intf, xpad); error = xpad_init_output(intf, xpad);
if (error) if (error)
goto fail2; goto fail3;
error = xpad_init_ff(xpad); error = xpad_init_ff(xpad);
if (error) if (error)
goto fail3; goto fail4;
error = xpad_led_probe(xpad); error = xpad_led_probe(xpad);
if (error) if (error)
goto fail3; goto fail5;
ep_irq_in = &intf->cur_altsetting->endpoint[0].desc; ep_irq_in = &intf->cur_altsetting->endpoint[0].desc;
usb_fill_int_urb(xpad->irq_in, udev, usb_fill_int_urb(xpad->irq_in, udev,
...@@ -907,34 +917,26 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id ...@@ -907,34 +917,26 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
error = input_register_device(xpad->dev); error = input_register_device(xpad->dev);
if (error) if (error)
goto fail4; goto fail6;
usb_set_intfdata(intf, xpad); usb_set_intfdata(intf, xpad);
/*
* Submit the int URB immediatly rather than waiting for open
* because we get status messages from the device whether
* or not any controllers are attached. In fact, it's
* exactly the message that a controller has arrived that
* we're waiting for.
*/
if (xpad->xtype == XTYPE_XBOX360W) { if (xpad->xtype == XTYPE_XBOX360W) {
xpad->irq_in->dev = xpad->udev;
error = usb_submit_urb(xpad->irq_in, GFP_KERNEL);
if (error)
goto fail4;
/* /*
* Setup the message to set the LEDs on the * Setup the message to set the LEDs on the
* controller when it shows up * controller when it shows up
*/ */
xpad->bulk_out = usb_alloc_urb(0, GFP_KERNEL); xpad->bulk_out = usb_alloc_urb(0, GFP_KERNEL);
if(!xpad->bulk_out) if (!xpad->bulk_out) {
goto fail5; error = -ENOMEM;
goto fail7;
}
xpad->bdata = kzalloc(XPAD_PKT_LEN, GFP_KERNEL); xpad->bdata = kzalloc(XPAD_PKT_LEN, GFP_KERNEL);
if(!xpad->bdata) if (!xpad->bdata) {
goto fail6; error = -ENOMEM;
goto fail8;
}
xpad->bdata[2] = 0x08; xpad->bdata[2] = 0x08;
switch (intf->cur_altsetting->desc.bInterfaceNumber) { switch (intf->cur_altsetting->desc.bInterfaceNumber) {
...@@ -955,14 +957,31 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id ...@@ -955,14 +957,31 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
usb_fill_bulk_urb(xpad->bulk_out, udev, usb_fill_bulk_urb(xpad->bulk_out, udev,
usb_sndbulkpipe(udev, ep_irq_in->bEndpointAddress), usb_sndbulkpipe(udev, ep_irq_in->bEndpointAddress),
xpad->bdata, XPAD_PKT_LEN, xpad_bulk_out, xpad); xpad->bdata, XPAD_PKT_LEN, xpad_bulk_out, xpad);
/*
* Submit the int URB immediately rather than waiting for open
* because we get status messages from the device whether
* or not any controllers are attached. In fact, it's
* exactly the message that a controller has arrived that
* we're waiting for.
*/
xpad->irq_in->dev = xpad->udev;
error = usb_submit_urb(xpad->irq_in, GFP_KERNEL);
if (error)
goto fail9;
} }
return 0; return 0;
fail6: usb_free_urb(xpad->bulk_out); fail9: kfree(xpad->bdata);
fail5: usb_kill_urb(xpad->irq_in); fail8: usb_free_urb(xpad->bulk_out);
fail4: usb_free_urb(xpad->irq_in); fail7: input_unregister_device(input_dev);
fail3: xpad_deinit_output(xpad); input_dev = NULL;
fail6: xpad_led_disconnect(xpad);
fail5: if (input_dev)
input_ff_destroy(input_dev);
fail4: xpad_deinit_output(xpad);
fail3: usb_free_urb(xpad->irq_in);
fail2: usb_free_coherent(udev, XPAD_PKT_LEN, xpad->idata, xpad->idata_dma); fail2: usb_free_coherent(udev, XPAD_PKT_LEN, xpad->idata, xpad->idata_dma);
fail1: input_free_device(input_dev); fail1: input_free_device(input_dev);
kfree(xpad); kfree(xpad);
...@@ -974,21 +993,24 @@ static void xpad_disconnect(struct usb_interface *intf) ...@@ -974,21 +993,24 @@ static void xpad_disconnect(struct usb_interface *intf)
{ {
struct usb_xpad *xpad = usb_get_intfdata (intf); struct usb_xpad *xpad = usb_get_intfdata (intf);
usb_set_intfdata(intf, NULL); xpad_led_disconnect(xpad);
if (xpad) { input_unregister_device(xpad->dev);
xpad_led_disconnect(xpad); xpad_deinit_output(xpad);
input_unregister_device(xpad->dev);
xpad_deinit_output(xpad); if (xpad->xtype == XTYPE_XBOX360W) {
if (xpad->xtype == XTYPE_XBOX360W) { usb_kill_urb(xpad->bulk_out);
usb_kill_urb(xpad->bulk_out); usb_free_urb(xpad->bulk_out);
usb_free_urb(xpad->bulk_out); usb_kill_urb(xpad->irq_in);
usb_kill_urb(xpad->irq_in);
}
usb_free_urb(xpad->irq_in);
usb_free_coherent(xpad->udev, XPAD_PKT_LEN,
xpad->idata, xpad->idata_dma);
kfree(xpad);
} }
usb_free_urb(xpad->irq_in);
usb_free_coherent(xpad->udev, XPAD_PKT_LEN,
xpad->idata, xpad->idata_dma);
kfree(xpad->bdata);
kfree(xpad);
usb_set_intfdata(intf, NULL);
} }
static struct usb_driver xpad_driver = { static struct usb_driver xpad_driver = {
...@@ -1000,10 +1022,7 @@ static struct usb_driver xpad_driver = { ...@@ -1000,10 +1022,7 @@ static struct usb_driver xpad_driver = {
static int __init usb_xpad_init(void) static int __init usb_xpad_init(void)
{ {
int result = usb_register(&xpad_driver); return usb_register(&xpad_driver);
if (result == 0)
printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_DESC "\n");
return result;
} }
static void __exit usb_xpad_exit(void) static void __exit usb_xpad_exit(void)
......
...@@ -196,20 +196,22 @@ config KEYBOARD_GPIO_POLLED ...@@ -196,20 +196,22 @@ config KEYBOARD_GPIO_POLLED
module will be called gpio_keys_polled. module will be called gpio_keys_polled.
config KEYBOARD_TCA6416 config KEYBOARD_TCA6416
tristate "TCA6416 Keypad Support" tristate "TCA6416/TCA6408A Keypad Support"
depends on I2C depends on I2C
help help
This driver implements basic keypad functionality This driver implements basic keypad functionality
for keys connected through TCA6416 IO expander for keys connected through TCA6416/TCA6408A IO expanders.
Say Y here if your device has keys connected to Say Y here if your device has keys connected to
TCA6416 IO expander. Your board-specific setup logic TCA6416/TCA6408A IO expander. Your board-specific setup logic
must also provide pin-mask details(of which TCA6416 pins must also provide pin-mask details(of which TCA6416 pins
are used for keypad). are used for keypad).
If enabled the complete TCA6416 device will be managed through If enabled the entire TCA6416 device will be managed through
this driver. this driver.
To compile this driver as a module, choose M here: the
module will be called tca6416_keypad.
config KEYBOARD_MATRIX config KEYBOARD_MATRIX
tristate "GPIO driven matrix keypad support" tristate "GPIO driven matrix keypad support"
...@@ -459,6 +461,15 @@ config KEYBOARD_OMAP4 ...@@ -459,6 +461,15 @@ config KEYBOARD_OMAP4
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called omap4-keypad. module will be called omap4-keypad.
config KEYBOARD_SPEAR
tristate "ST SPEAR keyboard support"
depends on PLAT_SPEAR
help
Say Y here if you want to use the SPEAR keyboard.
To compile this driver as a module, choose M here: the
module will be called spear-keboard.
config KEYBOARD_TNETV107X config KEYBOARD_TNETV107X
tristate "TI TNETV107X keypad support" tristate "TI TNETV107X keypad support"
depends on ARCH_DAVINCI_TNETV107X depends on ARCH_DAVINCI_TNETV107X
......
...@@ -38,6 +38,7 @@ obj-$(CONFIG_KEYBOARD_PXA930_ROTARY) += pxa930_rotary.o ...@@ -38,6 +38,7 @@ obj-$(CONFIG_KEYBOARD_PXA930_ROTARY) += pxa930_rotary.o
obj-$(CONFIG_KEYBOARD_QT2160) += qt2160.o obj-$(CONFIG_KEYBOARD_QT2160) += qt2160.o
obj-$(CONFIG_KEYBOARD_SAMSUNG) += samsung-keypad.o obj-$(CONFIG_KEYBOARD_SAMSUNG) += samsung-keypad.o
obj-$(CONFIG_KEYBOARD_SH_KEYSC) += sh_keysc.o obj-$(CONFIG_KEYBOARD_SH_KEYSC) += sh_keysc.o
obj-$(CONFIG_KEYBOARD_SPEAR) += spear-keyboard.o
obj-$(CONFIG_KEYBOARD_STMPE) += stmpe-keypad.o obj-$(CONFIG_KEYBOARD_STMPE) += stmpe-keypad.o
obj-$(CONFIG_KEYBOARD_STOWAWAY) += stowaway.o obj-$(CONFIG_KEYBOARD_STOWAWAY) += stowaway.o
obj-$(CONFIG_KEYBOARD_SUNKBD) += sunkbd.o obj-$(CONFIG_KEYBOARD_SUNKBD) += sunkbd.o
......
/*
* SPEAr Keyboard Driver
* Based on omap-keypad driver
*
* Copyright (C) 2010 ST Microelectronics
* Rajeev Kumar<rajeev-dlh.kumar@st.com>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
#include <linux/clk.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/input.h>
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/pm_wakeup.h>
#include <linux/slab.h>
#include <linux/types.h>
#include <plat/keyboard.h>
/* Keyboard Registers */
#define MODE_REG 0x00 /* 16 bit reg */
#define STATUS_REG 0x0C /* 2 bit reg */
#define DATA_REG 0x10 /* 8 bit reg */
#define INTR_MASK 0x54
/* Register Values */
/*
* pclk freq mask = (APB FEQ -1)= 82 MHZ.Programme bit 15-9 in mode
* control register as 1010010(82MHZ)
*/
#define PCLK_FREQ_MSK 0xA400 /* 82 MHz */
#define START_SCAN 0x0100
#define SCAN_RATE_10 0x0000
#define SCAN_RATE_20 0x0004
#define SCAN_RATE_40 0x0008
#define SCAN_RATE_80 0x000C
#define MODE_KEYBOARD 0x0002
#define DATA_AVAIL 0x2
#define KEY_MASK 0xFF000000
#define KEY_VALUE 0x00FFFFFF
#define ROW_MASK 0xF0
#define COLUMN_MASK 0x0F
#define ROW_SHIFT 4
struct spear_kbd {
struct input_dev *input;
struct resource *res;
void __iomem *io_base;
struct clk *clk;
unsigned int irq;
unsigned short last_key;
unsigned short keycodes[256];
};
static irqreturn_t spear_kbd_interrupt(int irq, void *dev_id)
{
struct spear_kbd *kbd = dev_id;
struct input_dev *input = kbd->input;
unsigned int key;
u8 sts, val;
sts = readb(kbd->io_base + STATUS_REG);
if (sts & DATA_AVAIL)
return IRQ_NONE;
if (kbd->last_key != KEY_RESERVED) {
input_report_key(input, kbd->last_key, 0);
kbd->last_key = KEY_RESERVED;
}
/* following reads active (row, col) pair */
val = readb(kbd->io_base + DATA_REG);
key = kbd->keycodes[val];
input_event(input, EV_MSC, MSC_SCAN, val);
input_report_key(input, key, 1);
input_sync(input);
kbd->last_key = key;
/* clear interrupt */
writeb(0, kbd->io_base + STATUS_REG);
return IRQ_HANDLED;
}
static int spear_kbd_open(struct input_dev *dev)
{
struct spear_kbd *kbd = input_get_drvdata(dev);
int error;
u16 val;
kbd->last_key = KEY_RESERVED;
error = clk_enable(kbd->clk);
if (error)
return error;
/* program keyboard */
val = SCAN_RATE_80 | MODE_KEYBOARD | PCLK_FREQ_MSK;
writew(val, kbd->io_base + MODE_REG);
writeb(1, kbd->io_base + STATUS_REG);
/* start key scan */
val = readw(kbd->io_base + MODE_REG);
val |= START_SCAN;
writew(val, kbd->io_base + MODE_REG);
return 0;
}
static void spear_kbd_close(struct input_dev *dev)
{
struct spear_kbd *kbd = input_get_drvdata(dev);
u16 val;
/* stop key scan */
val = readw(kbd->io_base + MODE_REG);
val &= ~START_SCAN;
writew(val, kbd->io_base + MODE_REG);
clk_disable(kbd->clk);
kbd->last_key = KEY_RESERVED;
}
static int __devinit spear_kbd_probe(struct platform_device *pdev)
{
const struct kbd_platform_data *pdata = pdev->dev.platform_data;
const struct matrix_keymap_data *keymap;
struct spear_kbd *kbd;
struct input_dev *input_dev;
struct resource *res;
int irq;
int error;
if (!pdata) {
dev_err(&pdev->dev, "Invalid platform data\n");
return -EINVAL;
}
keymap = pdata->keymap;
if (!keymap) {
dev_err(&pdev->dev, "no keymap defined\n");
return -EINVAL;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(&pdev->dev, "no keyboard resource defined\n");
return -EBUSY;
}
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
dev_err(&pdev->dev, "not able to get irq for the device\n");
return irq;
}
kbd = kzalloc(sizeof(*kbd), GFP_KERNEL);
input_dev = input_allocate_device();
if (!kbd || !input_dev) {
dev_err(&pdev->dev, "out of memory\n");
error = -ENOMEM;
goto err_free_mem;
}
kbd->input = input_dev;
kbd->irq = irq;
kbd->res = request_mem_region(res->start, resource_size(res),
pdev->name);
if (!kbd->res) {
dev_err(&pdev->dev, "keyboard region already claimed\n");
error = -EBUSY;
goto err_free_mem;
}
kbd->io_base = ioremap(res->start, resource_size(res));
if (!kbd->io_base) {
dev_err(&pdev->dev, "ioremap failed for kbd_region\n");
error = -ENOMEM;
goto err_release_mem_region;
}
kbd->clk = clk_get(&pdev->dev, NULL);
if (IS_ERR(kbd->clk)) {
error = PTR_ERR(kbd->clk);
goto err_iounmap;
}
input_dev->name = "Spear Keyboard";
input_dev->phys = "keyboard/input0";
input_dev->dev.parent = &pdev->dev;
input_dev->id.bustype = BUS_HOST;
input_dev->id.vendor = 0x0001;
input_dev->id.product = 0x0001;
input_dev->id.version = 0x0100;
input_dev->open = spear_kbd_open;
input_dev->close = spear_kbd_close;
__set_bit(EV_KEY, input_dev->evbit);
if (pdata->rep)
__set_bit(EV_REP, input_dev->evbit);
input_set_capability(input_dev, EV_MSC, MSC_SCAN);
input_dev->keycode = kbd->keycodes;
input_dev->keycodesize = sizeof(kbd->keycodes[0]);
input_dev->keycodemax = ARRAY_SIZE(kbd->keycodes);
matrix_keypad_build_keymap(keymap, ROW_SHIFT,
input_dev->keycode, input_dev->keybit);
input_set_drvdata(input_dev, kbd);
error = request_irq(irq, spear_kbd_interrupt, 0, "keyboard", kbd);
if (error) {
dev_err(&pdev->dev, "request_irq fail\n");
goto err_put_clk;
}
error = input_register_device(input_dev);
if (error) {
dev_err(&pdev->dev, "Unable to register keyboard device\n");
goto err_free_irq;
}
device_init_wakeup(&pdev->dev, 1);
platform_set_drvdata(pdev, kbd);
return 0;
err_free_irq:
free_irq(kbd->irq, kbd);
err_put_clk:
clk_put(kbd->clk);
err_iounmap:
iounmap(kbd->io_base);
err_release_mem_region:
release_mem_region(res->start, resource_size(res));
err_free_mem:
input_free_device(input_dev);
kfree(kbd);
return error;
}
static int __devexit spear_kbd_remove(struct platform_device *pdev)
{
struct spear_kbd *kbd = platform_get_drvdata(pdev);
free_irq(kbd->irq, kbd);
input_unregister_device(kbd->input);
clk_put(kbd->clk);
iounmap(kbd->io_base);
release_mem_region(kbd->res->start, resource_size(kbd->res));
kfree(kbd);
device_init_wakeup(&pdev->dev, 1);
platform_set_drvdata(pdev, NULL);
return 0;
}
#ifdef CONFIG_PM
static int spear_kbd_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct spear_kbd *kbd = platform_get_drvdata(pdev);
struct input_dev *input_dev = kbd->input;
mutex_lock(&input_dev->mutex);
if (input_dev->users)
clk_enable(kbd->clk);
if (device_may_wakeup(&pdev->dev))
enable_irq_wake(kbd->irq);
mutex_unlock(&input_dev->mutex);
return 0;
}
static int spear_kbd_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct spear_kbd *kbd = platform_get_drvdata(pdev);
struct input_dev *input_dev = kbd->input;
mutex_lock(&input_dev->mutex);
if (device_may_wakeup(&pdev->dev))
disable_irq_wake(kbd->irq);
if (input_dev->users)
clk_enable(kbd->clk);
mutex_unlock(&input_dev->mutex);
return 0;
}
static const struct dev_pm_ops spear_kbd_pm_ops = {
.suspend = spear_kbd_suspend,
.resume = spear_kbd_resume,
};
#endif
static struct platform_driver spear_kbd_driver = {
.probe = spear_kbd_probe,
.remove = __devexit_p(spear_kbd_remove),
.driver = {
.name = "keyboard",
.owner = THIS_MODULE,
#ifdef CONFIG_PM
.pm = &spear_kbd_pm_ops,
#endif
},
};
static int __init spear_kbd_init(void)
{
return platform_driver_register(&spear_kbd_driver);
}
module_init(spear_kbd_init);
static void __exit spear_kbd_exit(void)
{
platform_driver_unregister(&spear_kbd_driver);
}
module_exit(spear_kbd_exit);
MODULE_AUTHOR("Rajeev Kumar");
MODULE_DESCRIPTION("SPEAr Keyboard Driver");
MODULE_LICENSE("GPL");
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
static const struct i2c_device_id tca6416_id[] = { static const struct i2c_device_id tca6416_id[] = {
{ "tca6416-keys", 16, }, { "tca6416-keys", 16, },
{ "tca6408-keys", 8, },
{ } { }
}; };
MODULE_DEVICE_TABLE(i2c, tca6416_id); MODULE_DEVICE_TABLE(i2c, tca6416_id);
...@@ -46,8 +47,9 @@ struct tca6416_keypad_chip { ...@@ -46,8 +47,9 @@ struct tca6416_keypad_chip {
struct i2c_client *client; struct i2c_client *client;
struct input_dev *input; struct input_dev *input;
struct delayed_work dwork; struct delayed_work dwork;
u16 pinmask; int io_size;
int irqnum; int irqnum;
u16 pinmask;
bool use_polling; bool use_polling;
struct tca6416_button buttons[0]; struct tca6416_button buttons[0];
}; };
...@@ -56,7 +58,9 @@ static int tca6416_write_reg(struct tca6416_keypad_chip *chip, int reg, u16 val) ...@@ -56,7 +58,9 @@ static int tca6416_write_reg(struct tca6416_keypad_chip *chip, int reg, u16 val)
{ {
int error; int error;
error = i2c_smbus_write_word_data(chip->client, reg << 1, val); error = chip->io_size > 8 ?
i2c_smbus_write_word_data(chip->client, reg << 1, val) :
i2c_smbus_write_byte_data(chip->client, reg, val);
if (error < 0) { if (error < 0) {
dev_err(&chip->client->dev, dev_err(&chip->client->dev,
"%s failed, reg: %d, val: %d, error: %d\n", "%s failed, reg: %d, val: %d, error: %d\n",
...@@ -71,7 +75,9 @@ static int tca6416_read_reg(struct tca6416_keypad_chip *chip, int reg, u16 *val) ...@@ -71,7 +75,9 @@ static int tca6416_read_reg(struct tca6416_keypad_chip *chip, int reg, u16 *val)
{ {
int retval; int retval;
retval = i2c_smbus_read_word_data(chip->client, reg << 1); retval = chip->io_size > 8 ?
i2c_smbus_read_word_data(chip->client, reg << 1) :
i2c_smbus_read_byte_data(chip->client, reg);
if (retval < 0) { if (retval < 0) {
dev_err(&chip->client->dev, "%s failed, reg: %d, error: %d\n", dev_err(&chip->client->dev, "%s failed, reg: %d, error: %d\n",
__func__, reg, retval); __func__, reg, retval);
...@@ -224,6 +230,7 @@ static int __devinit tca6416_keypad_probe(struct i2c_client *client, ...@@ -224,6 +230,7 @@ static int __devinit tca6416_keypad_probe(struct i2c_client *client,
chip->client = client; chip->client = client;
chip->input = input; chip->input = input;
chip->io_size = id->driver_data;
chip->pinmask = pdata->pinmask; chip->pinmask = pdata->pinmask;
chip->use_polling = pdata->use_polling; chip->use_polling = pdata->use_polling;
......
...@@ -448,4 +448,28 @@ config INPUT_ADXL34X_SPI ...@@ -448,4 +448,28 @@ config INPUT_ADXL34X_SPI
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called adxl34x-spi. module will be called adxl34x-spi.
config INPUT_CMA3000
tristate "VTI CMA3000 Tri-axis accelerometer"
help
Say Y here if you want to use VTI CMA3000_D0x Accelerometer
driver
This driver currently only supports I2C interface to the
controller. Also select the I2C method.
If unsure, say N
To compile this driver as a module, choose M here: the
module will be called cma3000_d0x.
config INPUT_CMA3000_I2C
tristate "Support I2C bus connection"
depends on INPUT_CMA3000 && I2C
help
Say Y here if you want to use VTI CMA3000_D0x Accelerometer
through I2C interface.
To compile this driver as a module, choose M here: the
module will be called cma3000_d0x_i2c.
endif endif
...@@ -18,6 +18,8 @@ obj-$(CONFIG_INPUT_ATI_REMOTE2) += ati_remote2.o ...@@ -18,6 +18,8 @@ obj-$(CONFIG_INPUT_ATI_REMOTE2) += ati_remote2.o
obj-$(CONFIG_INPUT_ATLAS_BTNS) += atlas_btns.o obj-$(CONFIG_INPUT_ATLAS_BTNS) += atlas_btns.o
obj-$(CONFIG_INPUT_BFIN_ROTARY) += bfin_rotary.o obj-$(CONFIG_INPUT_BFIN_ROTARY) += bfin_rotary.o
obj-$(CONFIG_INPUT_CM109) += cm109.o obj-$(CONFIG_INPUT_CM109) += cm109.o
obj-$(CONFIG_INPUT_CMA3000) += cma3000_d0x.o
obj-$(CONFIG_INPUT_CMA3000_I2C) += cma3000_d0x_i2c.o
obj-$(CONFIG_INPUT_COBALT_BTNS) += cobalt_btns.o obj-$(CONFIG_INPUT_COBALT_BTNS) += cobalt_btns.o
obj-$(CONFIG_INPUT_DM355EVM) += dm355evm_keys.o obj-$(CONFIG_INPUT_DM355EVM) += dm355evm_keys.o
obj-$(CONFIG_HP_SDC_RTC) += hp_sdc_rtc.o obj-$(CONFIG_HP_SDC_RTC) += hp_sdc_rtc.o
......
/*
* VTI CMA3000_D0x Accelerometer driver
*
* Copyright (C) 2010 Texas Instruments
* Author: Hemanth V <hemanthv@ti.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License 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.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/types.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/input/cma3000.h>
#include "cma3000_d0x.h"
#define CMA3000_WHOAMI 0x00
#define CMA3000_REVID 0x01
#define CMA3000_CTRL 0x02
#define CMA3000_STATUS 0x03
#define CMA3000_RSTR 0x04
#define CMA3000_INTSTATUS 0x05
#define CMA3000_DOUTX 0x06
#define CMA3000_DOUTY 0x07
#define CMA3000_DOUTZ 0x08
#define CMA3000_MDTHR 0x09
#define CMA3000_MDFFTMR 0x0A
#define CMA3000_FFTHR 0x0B
#define CMA3000_RANGE2G (1 << 7)
#define CMA3000_RANGE8G (0 << 7)
#define CMA3000_BUSI2C (0 << 4)
#define CMA3000_MODEMASK (7 << 1)
#define CMA3000_GRANGEMASK (1 << 7)
#define CMA3000_STATUS_PERR 1
#define CMA3000_INTSTATUS_FFDET (1 << 2)
/* Settling time delay in ms */
#define CMA3000_SETDELAY 30
/* Delay for clearing interrupt in us */
#define CMA3000_INTDELAY 44
/*
* Bit weights in mg for bit 0, other bits need
* multipy factor 2^n. Eight bit is the sign bit.
*/
#define BIT_TO_2G 18
#define BIT_TO_8G 71
struct cma3000_accl_data {
const struct cma3000_bus_ops *bus_ops;
const struct cma3000_platform_data *pdata;
struct device *dev;
struct input_dev *input_dev;
int bit_to_mg;
int irq;
int g_range;
u8 mode;
struct mutex mutex;
bool opened;
bool suspended;
};
#define CMA3000_READ(data, reg, msg) \
(data->bus_ops->read(data->dev, reg, msg))
#define CMA3000_SET(data, reg, val, msg) \
((data)->bus_ops->write(data->dev, reg, val, msg))
/*
* Conversion for each of the eight modes to g, depending
* on G range i.e 2G or 8G. Some modes always operate in
* 8G.
*/
static int mode_to_mg[8][2] = {
{ 0, 0 },
{ BIT_TO_8G, BIT_TO_2G },
{ BIT_TO_8G, BIT_TO_2G },
{ BIT_TO_8G, BIT_TO_8G },
{ BIT_TO_8G, BIT_TO_8G },
{ BIT_TO_8G, BIT_TO_2G },
{ BIT_TO_8G, BIT_TO_2G },
{ 0, 0},
};
static void decode_mg(struct cma3000_accl_data *data, int *datax,
int *datay, int *dataz)
{
/* Data in 2's complement, convert to mg */
*datax = ((s8)*datax) * data->bit_to_mg;
*datay = ((s8)*datay) * data->bit_to_mg;
*dataz = ((s8)*dataz) * data->bit_to_mg;
}
static irqreturn_t cma3000_thread_irq(int irq, void *dev_id)
{
struct cma3000_accl_data *data = dev_id;
int datax, datay, dataz;
u8 ctrl, mode, range, intr_status;
intr_status = CMA3000_READ(data, CMA3000_INTSTATUS, "interrupt status");
if (intr_status < 0)
return IRQ_NONE;
/* Check if free fall is detected, report immediately */
if (intr_status & CMA3000_INTSTATUS_FFDET) {
input_report_abs(data->input_dev, ABS_MISC, 1);
input_sync(data->input_dev);
} else {
input_report_abs(data->input_dev, ABS_MISC, 0);
}
datax = CMA3000_READ(data, CMA3000_DOUTX, "X");
datay = CMA3000_READ(data, CMA3000_DOUTY, "Y");
dataz = CMA3000_READ(data, CMA3000_DOUTZ, "Z");
ctrl = CMA3000_READ(data, CMA3000_CTRL, "ctrl");
mode = (ctrl & CMA3000_MODEMASK) >> 1;
range = (ctrl & CMA3000_GRANGEMASK) >> 7;
data->bit_to_mg = mode_to_mg[mode][range];
/* Interrupt not for this device */
if (data->bit_to_mg == 0)
return IRQ_NONE;
/* Decode register values to milli g */
decode_mg(data, &datax, &datay, &dataz);
input_report_abs(data->input_dev, ABS_X, datax);
input_report_abs(data->input_dev, ABS_Y, datay);
input_report_abs(data->input_dev, ABS_Z, dataz);
input_sync(data->input_dev);
return IRQ_HANDLED;
}
static int cma3000_reset(struct cma3000_accl_data *data)
{
int val;
/* Reset sequence */
CMA3000_SET(data, CMA3000_RSTR, 0x02, "Reset");
CMA3000_SET(data, CMA3000_RSTR, 0x0A, "Reset");
CMA3000_SET(data, CMA3000_RSTR, 0x04, "Reset");
/* Settling time delay */
mdelay(10);
val = CMA3000_READ(data, CMA3000_STATUS, "Status");
if (val < 0) {
dev_err(data->dev, "Reset failed\n");
return val;
}
if (val & CMA3000_STATUS_PERR) {
dev_err(data->dev, "Parity Error\n");
return -EIO;
}
return 0;
}
static int cma3000_poweron(struct cma3000_accl_data *data)
{
const struct cma3000_platform_data *pdata = data->pdata;
u8 ctrl = 0;
int ret;
if (data->g_range == CMARANGE_2G) {
ctrl = (data->mode << 1) | CMA3000_RANGE2G;
} else if (data->g_range == CMARANGE_8G) {
ctrl = (data->mode << 1) | CMA3000_RANGE8G;
} else {
dev_info(data->dev,
"Invalid G range specified, assuming 8G\n");
ctrl = (data->mode << 1) | CMA3000_RANGE8G;
}
ctrl |= data->bus_ops->ctrl_mod;
CMA3000_SET(data, CMA3000_MDTHR, pdata->mdthr,
"Motion Detect Threshold");
CMA3000_SET(data, CMA3000_MDFFTMR, pdata->mdfftmr,
"Time register");
CMA3000_SET(data, CMA3000_FFTHR, pdata->ffthr,
"Free fall threshold");
ret = CMA3000_SET(data, CMA3000_CTRL, ctrl, "Mode setting");
if (ret < 0)
return -EIO;
msleep(CMA3000_SETDELAY);
return 0;
}
static int cma3000_poweroff(struct cma3000_accl_data *data)
{
int ret;
ret = CMA3000_SET(data, CMA3000_CTRL, CMAMODE_POFF, "Mode setting");
msleep(CMA3000_SETDELAY);
return ret;
}
static int cma3000_open(struct input_dev *input_dev)
{
struct cma3000_accl_data *data = input_get_drvdata(input_dev);
mutex_lock(&data->mutex);
if (!data->suspended)
cma3000_poweron(data);
data->opened = true;
mutex_unlock(&data->mutex);
return 0;
}
static void cma3000_close(struct input_dev *input_dev)
{
struct cma3000_accl_data *data = input_get_drvdata(input_dev);
mutex_lock(&data->mutex);
if (!data->suspended)
cma3000_poweroff(data);
data->opened = false;
mutex_unlock(&data->mutex);
}
void cma3000_suspend(struct cma3000_accl_data *data)
{
mutex_lock(&data->mutex);
if (!data->suspended && data->opened)
cma3000_poweroff(data);
data->suspended = true;
mutex_unlock(&data->mutex);
}
EXPORT_SYMBOL(cma3000_suspend);
void cma3000_resume(struct cma3000_accl_data *data)
{
mutex_lock(&data->mutex);
if (data->suspended && data->opened)
cma3000_poweron(data);
data->suspended = false;
mutex_unlock(&data->mutex);
}
EXPORT_SYMBOL(cma3000_resume);
struct cma3000_accl_data *cma3000_init(struct device *dev, int irq,
const struct cma3000_bus_ops *bops)
{
const struct cma3000_platform_data *pdata = dev->platform_data;
struct cma3000_accl_data *data;
struct input_dev *input_dev;
int rev;
int error;
if (!pdata) {
dev_err(dev, "platform data not found\n");
error = -EINVAL;
goto err_out;
}
/* if no IRQ return error */
if (irq == 0) {
error = -EINVAL;
goto err_out;
}
data = kzalloc(sizeof(struct cma3000_accl_data), GFP_KERNEL);
input_dev = input_allocate_device();
if (!data || !input_dev) {
error = -ENOMEM;
goto err_free_mem;
}
data->dev = dev;
data->input_dev = input_dev;
data->bus_ops = bops;
data->pdata = pdata;
data->irq = irq;
mutex_init(&data->mutex);
data->mode = pdata->mode;
if (data->mode < CMAMODE_DEFAULT || data->mode > CMAMODE_POFF) {
data->mode = CMAMODE_MOTDET;
dev_warn(dev,
"Invalid mode specified, assuming Motion Detect\n");
}
data->g_range = pdata->g_range;
if (data->g_range != CMARANGE_2G && data->g_range != CMARANGE_8G) {
dev_info(dev,
"Invalid G range specified, assuming 8G\n");
data->g_range = CMARANGE_8G;
}
input_dev->name = "cma3000-accelerometer";
input_dev->id.bustype = bops->bustype;
input_dev->open = cma3000_open;
input_dev->close = cma3000_close;
__set_bit(EV_ABS, input_dev->evbit);
input_set_abs_params(input_dev, ABS_X,
-data->g_range, data->g_range, pdata->fuzz_x, 0);
input_set_abs_params(input_dev, ABS_Y,
-data->g_range, data->g_range, pdata->fuzz_y, 0);
input_set_abs_params(input_dev, ABS_Z,
-data->g_range, data->g_range, pdata->fuzz_z, 0);
input_set_abs_params(input_dev, ABS_MISC, 0, 1, 0, 0);
input_set_drvdata(input_dev, data);
error = cma3000_reset(data);
if (error)
goto err_free_mem;
rev = CMA3000_READ(data, CMA3000_REVID, "Revid");
if (rev < 0) {
error = rev;
goto err_free_mem;
}
pr_info("CMA3000 Accelerometer: Revision %x\n", rev);
error = request_threaded_irq(irq, NULL, cma3000_thread_irq,
pdata->irqflags | IRQF_ONESHOT,
"cma3000_d0x", data);
if (error) {
dev_err(dev, "request_threaded_irq failed\n");
goto err_free_mem;
}
error = input_register_device(data->input_dev);
if (error) {
dev_err(dev, "Unable to register input device\n");
goto err_free_irq;
}
return data;
err_free_irq:
free_irq(irq, data);
err_free_mem:
input_free_device(input_dev);
kfree(data);
err_out:
return ERR_PTR(error);
}
EXPORT_SYMBOL(cma3000_init);
void cma3000_exit(struct cma3000_accl_data *data)
{
free_irq(data->irq, data);
input_unregister_device(data->input_dev);
kfree(data);
}
EXPORT_SYMBOL(cma3000_exit);
MODULE_DESCRIPTION("CMA3000-D0x Accelerometer Driver");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Hemanth V <hemanthv@ti.com>");
/*
* VTI CMA3000_D0x Accelerometer driver
*
* Copyright (C) 2010 Texas Instruments
* Author: Hemanth V <hemanthv@ti.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License 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.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _INPUT_CMA3000_H
#define _INPUT_CMA3000_H
#include <linux/types.h>
#include <linux/input.h>
struct device;
struct cma3000_accl_data;
struct cma3000_bus_ops {
u16 bustype;
u8 ctrl_mod;
int (*read)(struct device *, u8, char *);
int (*write)(struct device *, u8, u8, char *);
};
struct cma3000_accl_data *cma3000_init(struct device *dev, int irq,
const struct cma3000_bus_ops *bops);
void cma3000_exit(struct cma3000_accl_data *);
void cma3000_suspend(struct cma3000_accl_data *);
void cma3000_resume(struct cma3000_accl_data *);
#endif
/*
* Implements I2C interface for VTI CMA300_D0x Accelerometer driver
*
* Copyright (C) 2010 Texas Instruments
* Author: Hemanth V <hemanthv@ti.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License 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.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/input/cma3000.h>
#include "cma3000_d0x.h"
static int cma3000_i2c_set(struct device *dev,
u8 reg, u8 val, char *msg)
{
struct i2c_client *client = to_i2c_client(dev);
int ret;
ret = i2c_smbus_write_byte_data(client, reg, val);
if (ret < 0)
dev_err(&client->dev,
"%s failed (%s, %d)\n", __func__, msg, ret);
return ret;
}
static int cma3000_i2c_read(struct device *dev, u8 reg, char *msg)
{
struct i2c_client *client = to_i2c_client(dev);
int ret;
ret = i2c_smbus_read_byte_data(client, reg);
if (ret < 0)
dev_err(&client->dev,
"%s failed (%s, %d)\n", __func__, msg, ret);
return ret;
}
static const struct cma3000_bus_ops cma3000_i2c_bops = {
.bustype = BUS_I2C,
#define CMA3000_BUSI2C (0 << 4)
.ctrl_mod = CMA3000_BUSI2C,
.read = cma3000_i2c_read,
.write = cma3000_i2c_set,
};
static int __devinit cma3000_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct cma3000_accl_data *data;
data = cma3000_init(&client->dev, client->irq, &cma3000_i2c_bops);
if (IS_ERR(data))
return PTR_ERR(data);
i2c_set_clientdata(client, data);
return 0;
}
static int __devexit cma3000_i2c_remove(struct i2c_client *client)
{
struct cma3000_accl_data *data = i2c_get_clientdata(client);
cma3000_exit(data);
return 0;
}
#ifdef CONFIG_PM
static int cma3000_i2c_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct cma3000_accl_data *data = i2c_get_clientdata(client);
cma3000_suspend(data);
return 0;
}
static int cma3000_i2c_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct cma3000_accl_data *data = i2c_get_clientdata(client);
cma3000_resume(data);
return 0;
}
static const struct dev_pm_ops cma3000_i2c_pm_ops = {
.suspend = cma3000_i2c_suspend,
.resume = cma3000_i2c_resume,
};
#endif
static const struct i2c_device_id cma3000_i2c_id[] = {
{ "cma3000_d01", 0 },
{ },
};
MODULE_DEVICE_TABLE(i2c, cma3000_i2c_id);
static struct i2c_driver cma3000_i2c_driver = {
.probe = cma3000_i2c_probe,
.remove = __devexit_p(cma3000_i2c_remove),
.id_table = cma3000_i2c_id,
.driver = {
.name = "cma3000_i2c_accl",
.owner = THIS_MODULE,
#ifdef CONFIG_PM
.pm = &cma3000_i2c_pm_ops,
#endif
},
};
static int __init cma3000_i2c_init(void)
{
return i2c_add_driver(&cma3000_i2c_driver);
}
static void __exit cma3000_i2c_exit(void)
{
i2c_del_driver(&cma3000_i2c_driver);
}
module_init(cma3000_i2c_init);
module_exit(cma3000_i2c_exit);
MODULE_DESCRIPTION("CMA3000-D0x Accelerometer I2C Driver");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Hemanth V <hemanthv@ti.com>");
...@@ -169,19 +169,29 @@ static int __devexit pcf8574_kp_remove(struct i2c_client *client) ...@@ -169,19 +169,29 @@ static int __devexit pcf8574_kp_remove(struct i2c_client *client)
} }
#ifdef CONFIG_PM #ifdef CONFIG_PM
static int pcf8574_kp_resume(struct i2c_client *client) static int pcf8574_kp_resume(struct device *dev)
{ {
struct i2c_client *client = to_i2c_client(dev);
enable_irq(client->irq); enable_irq(client->irq);
return 0; return 0;
} }
static int pcf8574_kp_suspend(struct i2c_client *client, pm_message_t mesg) static int pcf8574_kp_suspend(struct device *dev)
{ {
struct i2c_client *client = to_i2c_client(dev);
disable_irq(client->irq); disable_irq(client->irq);
return 0; return 0;
} }
static const struct dev_pm_ops pcf8574_kp_pm_ops = {
.suspend = pcf8574_kp_suspend,
.resume = pcf8574_kp_resume,
};
#else #else
# define pcf8574_kp_resume NULL # define pcf8574_kp_resume NULL
# define pcf8574_kp_suspend NULL # define pcf8574_kp_suspend NULL
...@@ -197,11 +207,12 @@ static struct i2c_driver pcf8574_kp_driver = { ...@@ -197,11 +207,12 @@ static struct i2c_driver pcf8574_kp_driver = {
.driver = { .driver = {
.name = DRV_NAME, .name = DRV_NAME,
.owner = THIS_MODULE, .owner = THIS_MODULE,
#ifdef CONFIG_PM
.pm = &pcf8574_kp_pm_ops,
#endif
}, },
.probe = pcf8574_kp_probe, .probe = pcf8574_kp_probe,
.remove = __devexit_p(pcf8574_kp_remove), .remove = __devexit_p(pcf8574_kp_remove),
.suspend = pcf8574_kp_suspend,
.resume = pcf8574_kp_resume,
.id_table = pcf8574_kp_id, .id_table = pcf8574_kp_id,
}; };
......
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/miscdevice.h> #include <linux/miscdevice.h>
#include <linux/uinput.h> #include <linux/uinput.h>
#include <linux/input/mt.h>
#include "../input-compat.h" #include "../input-compat.h"
static int uinput_dev_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) static int uinput_dev_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
...@@ -406,8 +407,7 @@ static int uinput_setup_device(struct uinput_device *udev, const char __user *bu ...@@ -406,8 +407,7 @@ static int uinput_setup_device(struct uinput_device *udev, const char __user *bu
goto exit; goto exit;
if (test_bit(ABS_MT_SLOT, dev->absbit)) { if (test_bit(ABS_MT_SLOT, dev->absbit)) {
int nslot = input_abs_get_max(dev, ABS_MT_SLOT) + 1; int nslot = input_abs_get_max(dev, ABS_MT_SLOT) + 1;
input_mt_create_slots(dev, nslot); input_mt_init_slots(dev, nslot);
input_set_events_per_packet(dev, 6 * nslot);
} else if (test_bit(ABS_MT_POSITION_X, dev->absbit)) { } else if (test_bit(ABS_MT_POSITION_X, dev->absbit)) {
input_set_events_per_packet(dev, 60); input_set_events_per_packet(dev, 60);
} }
...@@ -680,6 +680,10 @@ static long uinput_ioctl_handler(struct file *file, unsigned int cmd, ...@@ -680,6 +680,10 @@ static long uinput_ioctl_handler(struct file *file, unsigned int cmd,
retval = uinput_set_bit(arg, swbit, SW_MAX); retval = uinput_set_bit(arg, swbit, SW_MAX);
break; break;
case UI_SET_PROPBIT:
retval = uinput_set_bit(arg, propbit, INPUT_PROP_MAX);
break;
case UI_SET_PHYS: case UI_SET_PHYS:
if (udev->state == UIST_CREATED) { if (udev->state == UIST_CREATED) {
retval = -EINVAL; retval = -EINVAL;
......
...@@ -40,6 +40,8 @@ ...@@ -40,6 +40,8 @@
#include "psmouse.h" #include "psmouse.h"
#include "hgpk.h" #include "hgpk.h"
#define ILLEGAL_XY 999999
static bool tpdebug; static bool tpdebug;
module_param(tpdebug, bool, 0644); module_param(tpdebug, bool, 0644);
MODULE_PARM_DESC(tpdebug, "enable debugging, dumping packets to KERN_DEBUG."); MODULE_PARM_DESC(tpdebug, "enable debugging, dumping packets to KERN_DEBUG.");
...@@ -47,48 +49,150 @@ MODULE_PARM_DESC(tpdebug, "enable debugging, dumping packets to KERN_DEBUG."); ...@@ -47,48 +49,150 @@ MODULE_PARM_DESC(tpdebug, "enable debugging, dumping packets to KERN_DEBUG.");
static int recalib_delta = 100; static int recalib_delta = 100;
module_param(recalib_delta, int, 0644); module_param(recalib_delta, int, 0644);
MODULE_PARM_DESC(recalib_delta, MODULE_PARM_DESC(recalib_delta,
"packets containing a delta this large will cause a recalibration."); "packets containing a delta this large will be discarded, and a "
"recalibration may be scheduled.");
static int jumpy_delay = 1000; static int jumpy_delay = 20;
module_param(jumpy_delay, int, 0644); module_param(jumpy_delay, int, 0644);
MODULE_PARM_DESC(jumpy_delay, MODULE_PARM_DESC(jumpy_delay,
"delay (ms) before recal after jumpiness detected"); "delay (ms) before recal after jumpiness detected");
static int spew_delay = 1000; static int spew_delay = 1;
module_param(spew_delay, int, 0644); module_param(spew_delay, int, 0644);
MODULE_PARM_DESC(spew_delay, MODULE_PARM_DESC(spew_delay,
"delay (ms) before recal after packet spew detected"); "delay (ms) before recal after packet spew detected");
static int recal_guard_time = 2000; static int recal_guard_time;
module_param(recal_guard_time, int, 0644); module_param(recal_guard_time, int, 0644);
MODULE_PARM_DESC(recal_guard_time, MODULE_PARM_DESC(recal_guard_time,
"interval (ms) during which recal will be restarted if packet received"); "interval (ms) during which recal will be restarted if packet received");
static int post_interrupt_delay = 1000; static int post_interrupt_delay = 40;
module_param(post_interrupt_delay, int, 0644); module_param(post_interrupt_delay, int, 0644);
MODULE_PARM_DESC(post_interrupt_delay, MODULE_PARM_DESC(post_interrupt_delay,
"delay (ms) before recal after recal interrupt detected"); "delay (ms) before recal after recal interrupt detected");
static bool autorecal = true;
module_param(autorecal, bool, 0644);
MODULE_PARM_DESC(autorecal, "enable recalibration in the driver");
static char hgpk_mode_name[16];
module_param_string(hgpk_mode, hgpk_mode_name, sizeof(hgpk_mode_name), 0644);
MODULE_PARM_DESC(hgpk_mode,
"default hgpk mode: mouse, glidesensor or pentablet");
static int hgpk_default_mode = HGPK_MODE_MOUSE;
static const char * const hgpk_mode_names[] = {
[HGPK_MODE_MOUSE] = "Mouse",
[HGPK_MODE_GLIDESENSOR] = "GlideSensor",
[HGPK_MODE_PENTABLET] = "PenTablet",
};
static int hgpk_mode_from_name(const char *buf, int len)
{
int i;
for (i = 0; i < ARRAY_SIZE(hgpk_mode_names); i++) {
const char *name = hgpk_mode_names[i];
if (strlen(name) == len && !strncasecmp(name, buf, len))
return i;
}
return HGPK_MODE_INVALID;
}
/*
* see if new value is within 20% of half of old value
*/
static int approx_half(int curr, int prev)
{
int belowhalf, abovehalf;
if (curr < 5 || prev < 5)
return 0;
belowhalf = (prev * 8) / 20;
abovehalf = (prev * 12) / 20;
return belowhalf < curr && curr <= abovehalf;
}
/* /*
* When the touchpad gets ultra-sensitive, one can keep their finger 1/2" * Throw out oddly large delta packets, and any that immediately follow whose
* above the pad and still have it send packets. This causes a jump cursor * values are each approximately half of the previous. It seems that the ALPS
* when one places their finger on the pad. We can probably detect the * firmware emits errant packets, and they get averaged out slowly.
* jump as we see a large deltas (>= 100px). In mouse mode, I've been
* unable to even come close to 100px deltas during normal usage, so I think
* this threshold is safe. If a large delta occurs, trigger a recalibration.
*/ */
static void hgpk_jumpy_hack(struct psmouse *psmouse, int x, int y) static int hgpk_discard_decay_hack(struct psmouse *psmouse, int x, int y)
{ {
struct hgpk_data *priv = psmouse->private; struct hgpk_data *priv = psmouse->private;
int avx, avy;
bool do_recal = false;
avx = abs(x);
avy = abs(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);
priv->xbigj = avx;
} else if (approx_half(avx, priv->xbigj)) {
hgpk_err(psmouse, "detected secondary %dpx jump in x\n", x);
priv->xbigj = avx;
priv->xsaw_secondary++;
} else {
if (priv->xbigj && priv->xsaw_secondary > 1)
do_recal = true;
priv->xbigj = 0;
priv->xsaw_secondary = 0;
}
if (avy > recalib_delta ||
(avy > recalib_delta / 2 && ((avy / 4) > priv->ylast))) {
hgpk_err(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);
priv->ybigj = avy;
priv->ysaw_secondary++;
} else {
if (priv->ybigj && priv->ysaw_secondary > 1)
do_recal = true;
priv->ybigj = 0;
priv->ysaw_secondary = 0;
}
if (abs(x) > recalib_delta || abs(y) > recalib_delta) { priv->xlast = avx;
hgpk_err(psmouse, ">%dpx jump detected (%d,%d)\n", priv->ylast = avy;
recalib_delta, x, y);
/* My car gets forty rods to the hogshead and that's the if (do_recal && jumpy_delay) {
* way I likes it! */ hgpk_err(psmouse, "scheduling recalibration\n");
psmouse_queue_work(psmouse, &priv->recalib_wq, psmouse_queue_work(psmouse, &priv->recalib_wq,
msecs_to_jiffies(jumpy_delay)); msecs_to_jiffies(jumpy_delay));
} }
return priv->xbigj || priv->ybigj;
}
static void hgpk_reset_spew_detection(struct hgpk_data *priv)
{
priv->spew_count = 0;
priv->dupe_count = 0;
priv->x_tally = 0;
priv->y_tally = 0;
priv->spew_flag = NO_SPEW;
}
static void hgpk_reset_hack_state(struct psmouse *psmouse)
{
struct hgpk_data *priv = psmouse->private;
priv->abs_x = priv->abs_y = -1;
priv->xlast = priv->ylast = ILLEGAL_XY;
priv->xbigj = priv->ybigj = 0;
priv->xsaw_secondary = priv->ysaw_secondary = 0;
hgpk_reset_spew_detection(priv);
} }
/* /*
...@@ -116,20 +220,57 @@ static void hgpk_spewing_hack(struct psmouse *psmouse, ...@@ -116,20 +220,57 @@ static void hgpk_spewing_hack(struct psmouse *psmouse,
if (l || r) if (l || r)
return; return;
/* don't track spew if the workaround feature has been turned off */
if (!spew_delay)
return;
if (abs(x) > 3 || abs(y) > 3) {
/* no spew, or spew ended */
hgpk_reset_spew_detection(priv);
return;
}
/* Keep a tally of the overall delta to the cursor position caused by
* the spew */
priv->x_tally += x; priv->x_tally += x;
priv->y_tally += y; priv->y_tally += y;
if (++priv->count > 100) { switch (priv->spew_flag) {
case NO_SPEW:
/* we're not spewing, but this packet might be the start */
priv->spew_flag = MAYBE_SPEWING;
/* fall-through */
case MAYBE_SPEWING:
priv->spew_count++;
if (priv->spew_count < SPEW_WATCH_COUNT)
break;
/* excessive spew detected, request recalibration */
priv->spew_flag = SPEW_DETECTED;
/* fall-through */
case SPEW_DETECTED:
/* only recalibrate when the overall delta to the cursor
* is really small. if the spew is causing significant cursor
* 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) { if (abs(priv->x_tally) < 3 && abs(priv->y_tally) < 3) {
hgpk_dbg(psmouse, "packet spew detected (%d,%d)\n", hgpk_err(psmouse, "packet spew detected (%d,%d)\n",
priv->x_tally, priv->y_tally); priv->x_tally, priv->y_tally);
priv->spew_flag = RECALIBRATING;
psmouse_queue_work(psmouse, &priv->recalib_wq, psmouse_queue_work(psmouse, &priv->recalib_wq,
msecs_to_jiffies(spew_delay)); msecs_to_jiffies(spew_delay));
} }
/* reset every 100 packets */
priv->count = 0; break;
priv->x_tally = 0; case RECALIBRATING:
priv->y_tally = 0; /* we already detected a spew and requested a recalibration,
* just wait for the queue to kick into action. */
break;
} }
} }
...@@ -143,25 +284,168 @@ static void hgpk_spewing_hack(struct psmouse *psmouse, ...@@ -143,25 +284,168 @@ static void hgpk_spewing_hack(struct psmouse *psmouse,
* swr/swl are the left/right buttons. * swr/swl are the left/right buttons.
* x-neg/y-neg are the x and y delta negative bits * x-neg/y-neg are the x and y delta negative bits
* x-over/y-over are the x and y overflow bits * x-over/y-over are the x and y overflow bits
*
* ---
*
* HGPK Advanced Mode - single-mode format
*
* byte 0(PT): 1 1 0 0 1 1 1 1
* byte 0(GS): 1 1 1 1 1 1 1 1
* byte 1: 0 x6 x5 x4 x3 x2 x1 x0
* byte 2(PT): 0 0 x9 x8 x7 ? pt-dsw 0
* byte 2(GS): 0 x10 x9 x8 x7 ? gs-dsw pt-dsw
* byte 3: 0 y9 y8 y7 1 0 swr swl
* byte 4: 0 y6 y5 y4 y3 y2 y1 y0
* byte 5: 0 z6 z5 z4 z3 z2 z1 z0
*
* ?'s are not defined in the protocol spec, may vary between models.
*
* swr/swl are the left/right buttons.
*
* pt-dsw/gs-dsw indicate that the pt/gs sensor is detecting a
* pen/finger
*/ */
static int hgpk_validate_byte(unsigned char *packet) static bool hgpk_is_byte_valid(struct psmouse *psmouse, unsigned char *packet)
{ {
return (packet[0] & 0x0C) != 0x08; struct hgpk_data *priv = psmouse->private;
int pktcnt = psmouse->pktcnt;
bool valid;
switch (priv->mode) {
case HGPK_MODE_MOUSE:
valid = (packet[0] & 0x0C) == 0x08;
break;
case HGPK_MODE_GLIDESENSOR:
valid = pktcnt == 1 ?
packet[0] == HGPK_GS : !(packet[pktcnt - 1] & 0x80);
break;
case HGPK_MODE_PENTABLET:
valid = pktcnt == 1 ?
packet[0] == HGPK_PT : !(packet[pktcnt - 1] & 0x80);
break;
default:
valid = false;
break;
}
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]);
return valid;
} }
static void hgpk_process_packet(struct psmouse *psmouse) static void hgpk_process_advanced_packet(struct psmouse *psmouse)
{ {
struct input_dev *dev = psmouse->dev; struct hgpk_data *priv = psmouse->private;
struct input_dev *idev = psmouse->dev;
unsigned char *packet = psmouse->packet; unsigned char *packet = psmouse->packet;
int x, y, left, right; int down = !!(packet[2] & 2);
int left = !!(packet[3] & 1);
int right = !!(packet[3] & 2);
int x = packet[1] | ((packet[2] & 0x78) << 4);
int y = packet[4] | ((packet[3] & 0x70) << 3);
if (priv->mode == HGPK_MODE_GLIDESENSOR) {
int pt_down = !!(packet[2] & 1);
int finger_down = !!(packet[2] & 2);
int z = packet[5];
input_report_abs(idev, ABS_PRESSURE, z);
if (tpdebug)
hgpk_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);
}
if (tpdebug)
hgpk_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);
input_report_key(idev, BTN_RIGHT, right);
/*
* If this packet says that the finger was removed, reset our position
* tracking so that we don't erroneously detect a jump on next press.
*/
if (!down) {
hgpk_reset_hack_state(psmouse);
goto done;
}
/*
* Weed out duplicate packets (we get quite a few, and they mess up
* our jump detection)
*/
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");
priv->spew_flag = RECALIBRATING;
psmouse_queue_work(psmouse, &priv->recalib_wq,
msecs_to_jiffies(spew_delay));
}
goto done;
}
left = packet[0] & 1; /* not a duplicate, continue with position reporting */
right = (packet[0] >> 1) & 1; priv->dupe_count = 0;
/* Don't apply hacks in PT mode, it seems reliable */
if (priv->mode != HGPK_MODE_PENTABLET && priv->abs_x != -1) {
int x_diff = priv->abs_x - x;
int y_diff = priv->abs_y - y;
if (hgpk_discard_decay_hack(psmouse, x_diff, y_diff)) {
if (tpdebug)
hgpk_dbg(psmouse, "discarding\n");
goto done;
}
hgpk_spewing_hack(psmouse, left, right, x_diff, y_diff);
}
x = packet[1] - ((packet[0] << 4) & 0x100); input_report_abs(idev, ABS_X, x);
y = ((packet[0] << 3) & 0x100) - packet[2]; input_report_abs(idev, ABS_Y, y);
priv->abs_x = x;
priv->abs_y = y;
done:
input_sync(idev);
}
static void hgpk_process_simple_packet(struct psmouse *psmouse)
{
struct input_dev *dev = psmouse->dev;
unsigned char *packet = psmouse->packet;
int left = packet[0] & 1;
int right = (packet[0] >> 1) & 1;
int x = packet[1] - ((packet[0] << 4) & 0x100);
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]);
if (hgpk_discard_decay_hack(psmouse, x, y)) {
if (tpdebug)
hgpk_dbg(psmouse, "discarding\n");
return;
}
hgpk_jumpy_hack(psmouse, x, y);
hgpk_spewing_hack(psmouse, left, right, x, y); hgpk_spewing_hack(psmouse, left, right, x, y);
if (tpdebug) if (tpdebug)
...@@ -180,15 +464,14 @@ static psmouse_ret_t hgpk_process_byte(struct psmouse *psmouse) ...@@ -180,15 +464,14 @@ static psmouse_ret_t hgpk_process_byte(struct psmouse *psmouse)
{ {
struct hgpk_data *priv = psmouse->private; struct hgpk_data *priv = psmouse->private;
if (hgpk_validate_byte(psmouse->packet)) { if (!hgpk_is_byte_valid(psmouse, psmouse->packet))
hgpk_dbg(psmouse, "%s: (%d) %02x %02x %02x\n",
__func__, psmouse->pktcnt, psmouse->packet[0],
psmouse->packet[1], psmouse->packet[2]);
return PSMOUSE_BAD_DATA; return PSMOUSE_BAD_DATA;
}
if (psmouse->pktcnt >= psmouse->pktsize) { if (psmouse->pktcnt >= psmouse->pktsize) {
hgpk_process_packet(psmouse); if (priv->mode == HGPK_MODE_MOUSE)
hgpk_process_simple_packet(psmouse);
else
hgpk_process_advanced_packet(psmouse);
return PSMOUSE_FULL_PACKET; return PSMOUSE_FULL_PACKET;
} }
...@@ -210,33 +493,176 @@ static psmouse_ret_t hgpk_process_byte(struct psmouse *psmouse) ...@@ -210,33 +493,176 @@ static psmouse_ret_t hgpk_process_byte(struct psmouse *psmouse)
return PSMOUSE_GOOD_DATA; return PSMOUSE_GOOD_DATA;
} }
static int hgpk_select_mode(struct psmouse *psmouse)
{
struct ps2dev *ps2dev = &psmouse->ps2dev;
struct hgpk_data *priv = psmouse->private;
int i;
int cmd;
/*
* 4 disables to enable advanced mode
* then 3 0xf2 bytes as the preamble for GS/PT selection
*/
const int advanced_init[] = {
PSMOUSE_CMD_DISABLE, PSMOUSE_CMD_DISABLE,
PSMOUSE_CMD_DISABLE, PSMOUSE_CMD_DISABLE,
0xf2, 0xf2, 0xf2,
};
switch (priv->mode) {
case HGPK_MODE_MOUSE:
psmouse->pktsize = 3;
break;
case HGPK_MODE_GLIDESENSOR:
case HGPK_MODE_PENTABLET:
psmouse->pktsize = 6;
/* Switch to 'Advanced mode.', four disables in a row. */
for (i = 0; i < ARRAY_SIZE(advanced_init); i++)
if (ps2_command(ps2dev, NULL, advanced_init[i]))
return -EIO;
/* select between GlideSensor (mouse) or PenTablet */
cmd = priv->mode == HGPK_MODE_GLIDESENSOR ?
PSMOUSE_CMD_SETSCALE11 : PSMOUSE_CMD_SETSCALE21;
if (ps2_command(ps2dev, NULL, cmd))
return -EIO;
break;
default:
return -EINVAL;
}
return 0;
}
static void hgpk_setup_input_device(struct input_dev *input,
struct input_dev *old_input,
enum hgpk_mode mode)
{
if (old_input) {
input->name = old_input->name;
input->phys = old_input->phys;
input->id = old_input->id;
input->dev.parent = old_input->dev.parent;
}
memset(input->evbit, 0, sizeof(input->evbit));
memset(input->relbit, 0, sizeof(input->relbit));
memset(input->keybit, 0, sizeof(input->keybit));
/* All modes report left and right buttons */
__set_bit(EV_KEY, input->evbit);
__set_bit(BTN_LEFT, input->keybit);
__set_bit(BTN_RIGHT, input->keybit);
switch (mode) {
case HGPK_MODE_MOUSE:
__set_bit(EV_REL, input->evbit);
__set_bit(REL_X, input->relbit);
__set_bit(REL_Y, input->relbit);
break;
case HGPK_MODE_GLIDESENSOR:
__set_bit(BTN_TOUCH, input->keybit);
__set_bit(BTN_TOOL_FINGER, input->keybit);
__set_bit(EV_ABS, input->evbit);
/* GlideSensor has pressure sensor, PenTablet does not */
input_set_abs_params(input, ABS_PRESSURE, 0, 15, 0, 0);
/* From device specs */
input_set_abs_params(input, ABS_X, 0, 399, 0, 0);
input_set_abs_params(input, ABS_Y, 0, 290, 0, 0);
/* Calculated by hand based on usable size (52mm x 38mm) */
input_abs_set_res(input, ABS_X, 8);
input_abs_set_res(input, ABS_Y, 8);
break;
case HGPK_MODE_PENTABLET:
__set_bit(BTN_TOUCH, input->keybit);
__set_bit(BTN_TOOL_FINGER, input->keybit);
__set_bit(EV_ABS, input->evbit);
/* From device specs */
input_set_abs_params(input, ABS_X, 0, 999, 0, 0);
input_set_abs_params(input, ABS_Y, 5, 239, 0, 0);
/* Calculated by hand based on usable size (156mm x 38mm) */
input_abs_set_res(input, ABS_X, 6);
input_abs_set_res(input, ABS_Y, 8);
break;
default:
BUG();
}
}
static int hgpk_reset_device(struct psmouse *psmouse, bool recalibrate)
{
int err;
psmouse_reset(psmouse);
if (recalibrate) {
struct ps2dev *ps2dev = &psmouse->ps2dev;
/* send the recalibrate request */
if (ps2_command(ps2dev, NULL, 0xf5) ||
ps2_command(ps2dev, NULL, 0xf5) ||
ps2_command(ps2dev, NULL, 0xe6) ||
ps2_command(ps2dev, NULL, 0xf5)) {
return -1;
}
/* according to ALPS, 150mS is required for recalibration */
msleep(150);
}
err = hgpk_select_mode(psmouse);
if (err) {
hgpk_err(psmouse, "failed to select mode\n");
return err;
}
hgpk_reset_hack_state(psmouse);
return 0;
}
static int hgpk_force_recalibrate(struct psmouse *psmouse) static int hgpk_force_recalibrate(struct psmouse *psmouse)
{ {
struct ps2dev *ps2dev = &psmouse->ps2dev; struct ps2dev *ps2dev = &psmouse->ps2dev;
struct hgpk_data *priv = psmouse->private; struct hgpk_data *priv = psmouse->private;
int err;
/* C-series touchpads added the recalibrate command */ /* C-series touchpads added the recalibrate command */
if (psmouse->model < HGPK_MODEL_C) if (psmouse->model < HGPK_MODEL_C)
return 0; return 0;
if (!autorecal) {
hgpk_dbg(psmouse, "recalibrations disabled, ignoring\n");
return 0;
}
hgpk_dbg(psmouse, "recalibrating touchpad..\n");
/* we don't want to race with the irq handler, nor with resyncs */ /* we don't want to race with the irq handler, nor with resyncs */
psmouse_set_state(psmouse, PSMOUSE_INITIALIZING); psmouse_set_state(psmouse, PSMOUSE_INITIALIZING);
/* start by resetting the device */ /* start by resetting the device */
psmouse_reset(psmouse); err = hgpk_reset_device(psmouse, true);
if (err)
/* send the recalibrate request */ return err;
if (ps2_command(ps2dev, NULL, 0xf5) ||
ps2_command(ps2dev, NULL, 0xf5) ||
ps2_command(ps2dev, NULL, 0xe6) ||
ps2_command(ps2dev, NULL, 0xf5)) {
return -1;
}
/* according to ALPS, 150mS is required for recalibration */
msleep(150);
/* XXX: If a finger is down during this delay, recalibration will /*
* XXX: If a finger is down during this delay, recalibration will
* detect capacitance incorrectly. This is a hardware bug, and * detect capacitance incorrectly. This is a hardware bug, and
* we don't have a good way to deal with it. The 2s window stuff * we don't have a good way to deal with it. The 2s window stuff
* (below) is our best option for now. * (below) is our best option for now.
...@@ -247,25 +673,35 @@ static int hgpk_force_recalibrate(struct psmouse *psmouse) ...@@ -247,25 +673,35 @@ static int hgpk_force_recalibrate(struct psmouse *psmouse)
psmouse_set_state(psmouse, PSMOUSE_ACTIVATED); psmouse_set_state(psmouse, PSMOUSE_ACTIVATED);
/* After we recalibrate, we shouldn't get any packets for 2s. If if (tpdebug)
* we do, it's likely that someone's finger was on the touchpad. hgpk_dbg(psmouse, "touchpad reactivated\n");
* If someone's finger *was* on the touchpad, it's probably
* miscalibrated. So, we should schedule another recalibration /*
* If we get packets right away after recalibrating, it's likely
* that a finger was on the touchpad. If so, it's probably
* miscalibrated, so we optionally schedule another.
*/ */
priv->recalib_window = jiffies + msecs_to_jiffies(recal_guard_time); if (recal_guard_time)
priv->recalib_window = jiffies +
msecs_to_jiffies(recal_guard_time);
return 0; return 0;
} }
/* /*
* This kills power to the touchpad; according to ALPS, current consumption * This puts the touchpad in a power saving mode; according to ALPS, current
* goes down to 50uA after running this. To turn power back on, we drive * consumption goes down to 50uA after running this. To turn power back on,
* MS-DAT low. * we drive MS-DAT low. Measuring with a 1mA resolution ammeter says that
* the current on the SUS_3.3V rail drops from 3mA or 4mA to 0 when we do this.
*
* We have no formal spec that details this operation -- the low-power
* sequence came from a long-lost email trail.
*/ */
static int hgpk_toggle_power(struct psmouse *psmouse, int enable) static int hgpk_toggle_powersave(struct psmouse *psmouse, int enable)
{ {
struct ps2dev *ps2dev = &psmouse->ps2dev; struct ps2dev *ps2dev = &psmouse->ps2dev;
int timeo; int timeo;
int err;
/* Added on D-series touchpads */ /* Added on D-series touchpads */
if (psmouse->model < HGPK_MODEL_D) if (psmouse->model < HGPK_MODEL_D)
...@@ -279,24 +715,27 @@ static int hgpk_toggle_power(struct psmouse *psmouse, int enable) ...@@ -279,24 +715,27 @@ static int hgpk_toggle_power(struct psmouse *psmouse, int enable)
* the controller. Once we get an ACK back from it, it * the controller. Once we get an ACK back from it, it
* means we can continue with the touchpad re-init. ALPS * means we can continue with the touchpad re-init. ALPS
* tells us that 1s should be long enough, so set that as * tells us that 1s should be long enough, so set that as
* the upper bound. * the upper bound. (in practice, it takes about 3 loops.)
*/ */
for (timeo = 20; timeo > 0; timeo--) { for (timeo = 20; timeo > 0; timeo--) {
if (!ps2_sendbyte(&psmouse->ps2dev, if (!ps2_sendbyte(&psmouse->ps2dev,
PSMOUSE_CMD_DISABLE, 20)) PSMOUSE_CMD_DISABLE, 20))
break; break;
msleep(50); msleep(25);
} }
psmouse_reset(psmouse); err = hgpk_reset_device(psmouse, false);
if (err) {
hgpk_err(psmouse, "Failed to reset device!\n");
return err;
}
/* should be all set, enable the touchpad */ /* should be all set, enable the touchpad */
ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_ENABLE); ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_ENABLE);
psmouse_set_state(psmouse, PSMOUSE_ACTIVATED); psmouse_set_state(psmouse, PSMOUSE_ACTIVATED);
hgpk_dbg(psmouse, "Touchpad powered up.\n");
} else { } else {
hgpk_dbg(psmouse, "Powering off touchpad.\n"); hgpk_dbg(psmouse, "Powering off touchpad.\n");
psmouse_set_state(psmouse, PSMOUSE_IGNORE);
if (ps2_command(ps2dev, NULL, 0xec) || if (ps2_command(ps2dev, NULL, 0xec) ||
ps2_command(ps2dev, NULL, 0xec) || ps2_command(ps2dev, NULL, 0xec) ||
...@@ -304,6 +743,8 @@ static int hgpk_toggle_power(struct psmouse *psmouse, int enable) ...@@ -304,6 +743,8 @@ static int hgpk_toggle_power(struct psmouse *psmouse, int enable)
return -1; return -1;
} }
psmouse_set_state(psmouse, PSMOUSE_IGNORE);
/* probably won't see an ACK, the touchpad will be off */ /* probably won't see an ACK, the touchpad will be off */
ps2_sendbyte(&psmouse->ps2dev, 0xec, 20); ps2_sendbyte(&psmouse->ps2dev, 0xec, 20);
} }
...@@ -319,17 +760,20 @@ static int hgpk_poll(struct psmouse *psmouse) ...@@ -319,17 +760,20 @@ static int hgpk_poll(struct psmouse *psmouse)
static int hgpk_reconnect(struct psmouse *psmouse) static int hgpk_reconnect(struct psmouse *psmouse)
{ {
/* During suspend/resume the ps2 rails remain powered. We don't want struct hgpk_data *priv = psmouse->private;
/*
* During suspend/resume the ps2 rails remain powered. We don't want
* to do a reset because it's flush data out of buffers; however, * to do a reset because it's flush data out of buffers; however,
* earlier prototypes (B1) had some brokenness that required a reset. */ * earlier prototypes (B1) had some brokenness that required a reset.
*/
if (olpc_board_at_least(olpc_board(0xb2))) if (olpc_board_at_least(olpc_board(0xb2)))
if (psmouse->ps2dev.serio->dev.power.power_state.event != if (psmouse->ps2dev.serio->dev.power.power_state.event !=
PM_EVENT_ON) PM_EVENT_ON)
return 0; return 0;
psmouse_reset(psmouse); priv->powered = 1;
return hgpk_reset_device(psmouse, false);
return 0;
} }
static ssize_t hgpk_show_powered(struct psmouse *psmouse, void *data, char *buf) static ssize_t hgpk_show_powered(struct psmouse *psmouse, void *data, char *buf)
...@@ -355,7 +799,7 @@ static ssize_t hgpk_set_powered(struct psmouse *psmouse, void *data, ...@@ -355,7 +799,7 @@ static ssize_t hgpk_set_powered(struct psmouse *psmouse, void *data,
* hgpk_toggle_power will deal w/ state so * hgpk_toggle_power will deal w/ state so
* we're not racing w/ irq * we're not racing w/ irq
*/ */
err = hgpk_toggle_power(psmouse, value); err = hgpk_toggle_powersave(psmouse, value);
if (!err) if (!err)
priv->powered = value; priv->powered = value;
} }
...@@ -366,6 +810,65 @@ static ssize_t hgpk_set_powered(struct psmouse *psmouse, void *data, ...@@ -366,6 +810,65 @@ static ssize_t hgpk_set_powered(struct psmouse *psmouse, void *data,
__PSMOUSE_DEFINE_ATTR(powered, S_IWUSR | S_IRUGO, NULL, __PSMOUSE_DEFINE_ATTR(powered, S_IWUSR | S_IRUGO, NULL,
hgpk_show_powered, hgpk_set_powered, false); hgpk_show_powered, hgpk_set_powered, false);
static ssize_t attr_show_mode(struct psmouse *psmouse, void *data, char *buf)
{
struct hgpk_data *priv = psmouse->private;
return sprintf(buf, "%s\n", hgpk_mode_names[priv->mode]);
}
static ssize_t attr_set_mode(struct psmouse *psmouse, void *data,
const char *buf, size_t len)
{
struct hgpk_data *priv = psmouse->private;
enum hgpk_mode old_mode = priv->mode;
enum hgpk_mode new_mode = hgpk_mode_from_name(buf, len);
struct input_dev *old_dev = psmouse->dev;
struct input_dev *new_dev;
int err;
if (new_mode == HGPK_MODE_INVALID)
return -EINVAL;
if (old_mode == new_mode)
return len;
new_dev = input_allocate_device();
if (!new_dev)
return -ENOMEM;
psmouse_set_state(psmouse, PSMOUSE_INITIALIZING);
/* Switch device into the new mode */
priv->mode = new_mode;
err = hgpk_reset_device(psmouse, false);
if (err)
goto err_try_restore;
hgpk_setup_input_device(new_dev, old_dev, new_mode);
psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
err = input_register_device(new_dev);
if (err)
goto err_try_restore;
psmouse->dev = new_dev;
input_unregister_device(old_dev);
return len;
err_try_restore:
input_free_device(new_dev);
priv->mode = old_mode;
hgpk_reset_device(psmouse, false);
return err;
}
PSMOUSE_DEFINE_ATTR(hgpk_mode, S_IWUSR | S_IRUGO, NULL,
attr_show_mode, attr_set_mode);
static ssize_t hgpk_trigger_recal_show(struct psmouse *psmouse, static ssize_t hgpk_trigger_recal_show(struct psmouse *psmouse,
void *data, char *buf) void *data, char *buf)
{ {
...@@ -401,6 +904,8 @@ static void hgpk_disconnect(struct psmouse *psmouse) ...@@ -401,6 +904,8 @@ static void hgpk_disconnect(struct psmouse *psmouse)
device_remove_file(&psmouse->ps2dev.serio->dev, device_remove_file(&psmouse->ps2dev.serio->dev,
&psmouse_attr_powered.dattr); &psmouse_attr_powered.dattr);
device_remove_file(&psmouse->ps2dev.serio->dev,
&psmouse_attr_hgpk_mode.dattr);
if (psmouse->model >= HGPK_MODEL_C) if (psmouse->model >= HGPK_MODEL_C)
device_remove_file(&psmouse->ps2dev.serio->dev, device_remove_file(&psmouse->ps2dev.serio->dev,
...@@ -416,14 +921,13 @@ static void hgpk_recalib_work(struct work_struct *work) ...@@ -416,14 +921,13 @@ static void hgpk_recalib_work(struct work_struct *work)
struct hgpk_data *priv = container_of(w, struct hgpk_data, recalib_wq); struct hgpk_data *priv = container_of(w, struct hgpk_data, recalib_wq);
struct psmouse *psmouse = priv->psmouse; struct psmouse *psmouse = priv->psmouse;
hgpk_dbg(psmouse, "recalibrating touchpad..\n");
if (hgpk_force_recalibrate(psmouse)) if (hgpk_force_recalibrate(psmouse))
hgpk_err(psmouse, "recalibration failed!\n"); hgpk_err(psmouse, "recalibration failed!\n");
} }
static int hgpk_register(struct psmouse *psmouse) static int hgpk_register(struct psmouse *psmouse)
{ {
struct hgpk_data *priv = psmouse->private;
int err; int err;
/* register handlers */ /* register handlers */
...@@ -431,13 +935,14 @@ static int hgpk_register(struct psmouse *psmouse) ...@@ -431,13 +935,14 @@ static int hgpk_register(struct psmouse *psmouse)
psmouse->poll = hgpk_poll; psmouse->poll = hgpk_poll;
psmouse->disconnect = hgpk_disconnect; psmouse->disconnect = hgpk_disconnect;
psmouse->reconnect = hgpk_reconnect; psmouse->reconnect = hgpk_reconnect;
psmouse->pktsize = 3;
/* Disable the idle resync. */ /* Disable the idle resync. */
psmouse->resync_time = 0; psmouse->resync_time = 0;
/* Reset after a lot of bad bytes. */ /* Reset after a lot of bad bytes. */
psmouse->resetafter = 1024; psmouse->resetafter = 1024;
hgpk_setup_input_device(psmouse->dev, NULL, priv->mode);
err = device_create_file(&psmouse->ps2dev.serio->dev, err = device_create_file(&psmouse->ps2dev.serio->dev,
&psmouse_attr_powered.dattr); &psmouse_attr_powered.dattr);
if (err) { if (err) {
...@@ -445,6 +950,13 @@ static int hgpk_register(struct psmouse *psmouse) ...@@ -445,6 +950,13 @@ static int hgpk_register(struct psmouse *psmouse)
return err; 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");
goto err_remove_powered;
}
/* C-series touchpads added the recalibrate command */ /* C-series touchpads added the recalibrate command */
if (psmouse->model >= HGPK_MODEL_C) { if (psmouse->model >= HGPK_MODEL_C) {
err = device_create_file(&psmouse->ps2dev.serio->dev, err = device_create_file(&psmouse->ps2dev.serio->dev,
...@@ -452,30 +964,40 @@ static int hgpk_register(struct psmouse *psmouse) ...@@ -452,30 +964,40 @@ static int hgpk_register(struct psmouse *psmouse)
if (err) { if (err) {
hgpk_err(psmouse, hgpk_err(psmouse,
"Failed creating 'recalibrate' sysfs node\n"); "Failed creating 'recalibrate' sysfs node\n");
device_remove_file(&psmouse->ps2dev.serio->dev, goto err_remove_mode;
&psmouse_attr_powered.dattr);
return err;
} }
} }
return 0; return 0;
err_remove_mode:
device_remove_file(&psmouse->ps2dev.serio->dev,
&psmouse_attr_hgpk_mode.dattr);
err_remove_powered:
device_remove_file(&psmouse->ps2dev.serio->dev,
&psmouse_attr_powered.dattr);
return err;
} }
int hgpk_init(struct psmouse *psmouse) int hgpk_init(struct psmouse *psmouse)
{ {
struct hgpk_data *priv; struct hgpk_data *priv;
int err = -ENOMEM; int err;
priv = kzalloc(sizeof(struct hgpk_data), GFP_KERNEL); priv = kzalloc(sizeof(struct hgpk_data), GFP_KERNEL);
if (!priv) if (!priv) {
err = -ENOMEM;
goto alloc_fail; goto alloc_fail;
}
psmouse->private = priv; psmouse->private = priv;
priv->psmouse = psmouse; priv->psmouse = psmouse;
priv->powered = true; priv->powered = true;
priv->mode = hgpk_default_mode;
INIT_DELAYED_WORK(&priv->recalib_wq, hgpk_recalib_work); INIT_DELAYED_WORK(&priv->recalib_wq, hgpk_recalib_work);
err = psmouse_reset(psmouse); err = hgpk_reset_device(psmouse, false);
if (err) if (err)
goto init_fail; goto init_fail;
...@@ -531,3 +1053,14 @@ int hgpk_detect(struct psmouse *psmouse, bool set_properties) ...@@ -531,3 +1053,14 @@ int hgpk_detect(struct psmouse *psmouse, bool set_properties)
return 0; return 0;
} }
void hgpk_module_init(void)
{
hgpk_default_mode = hgpk_mode_from_name(hgpk_mode_name,
strlen(hgpk_mode_name));
if (hgpk_default_mode == HGPK_MODE_INVALID) {
hgpk_default_mode = HGPK_MODE_MOUSE;
strlcpy(hgpk_mode_name, hgpk_mode_names[HGPK_MODE_MOUSE],
sizeof(hgpk_mode_name));
}
}
...@@ -5,6 +5,9 @@ ...@@ -5,6 +5,9 @@
#ifndef _HGPK_H #ifndef _HGPK_H
#define _HGPK_H #define _HGPK_H
#define HGPK_GS 0xff /* The GlideSensor */
#define HGPK_PT 0xcf /* The PenTablet */
enum hgpk_model_t { enum hgpk_model_t {
HGPK_MODEL_PREA = 0x0a, /* pre-B1s */ HGPK_MODEL_PREA = 0x0a, /* pre-B1s */
HGPK_MODEL_A = 0x14, /* found on B1s, PT disabled in hardware */ HGPK_MODEL_A = 0x14, /* found on B1s, PT disabled in hardware */
...@@ -13,12 +16,34 @@ enum hgpk_model_t { ...@@ -13,12 +16,34 @@ enum hgpk_model_t {
HGPK_MODEL_D = 0x50, /* C1, mass production */ HGPK_MODEL_D = 0x50, /* C1, mass production */
}; };
enum hgpk_spew_flag {
NO_SPEW,
MAYBE_SPEWING,
SPEW_DETECTED,
RECALIBRATING,
};
#define SPEW_WATCH_COUNT 42 /* at 12ms/packet, this is 1/2 second */
enum hgpk_mode {
HGPK_MODE_MOUSE,
HGPK_MODE_GLIDESENSOR,
HGPK_MODE_PENTABLET,
HGPK_MODE_INVALID
};
struct hgpk_data { struct hgpk_data {
struct psmouse *psmouse; struct psmouse *psmouse;
enum hgpk_mode mode;
bool powered; bool powered;
int count, x_tally, y_tally; /* hardware workaround stuff */ enum hgpk_spew_flag spew_flag;
int spew_count, x_tally, y_tally; /* spew detection */
unsigned long recalib_window; unsigned long recalib_window;
struct delayed_work recalib_wq; struct delayed_work recalib_wq;
int abs_x, abs_y;
int dupe_count;
int xbigj, ybigj, xlast, ylast; /* jumpiness detection */
int xsaw_secondary, ysaw_secondary; /* jumpiness detection */
}; };
#define hgpk_dbg(psmouse, format, arg...) \ #define hgpk_dbg(psmouse, format, arg...) \
...@@ -33,9 +58,13 @@ struct hgpk_data { ...@@ -33,9 +58,13 @@ struct hgpk_data {
dev_notice(&(psmouse)->ps2dev.serio->dev, format, ## arg) dev_notice(&(psmouse)->ps2dev.serio->dev, format, ## arg)
#ifdef CONFIG_MOUSE_PS2_OLPC #ifdef CONFIG_MOUSE_PS2_OLPC
void hgpk_module_init(void);
int hgpk_detect(struct psmouse *psmouse, bool set_properties); int hgpk_detect(struct psmouse *psmouse, bool set_properties);
int hgpk_init(struct psmouse *psmouse); int hgpk_init(struct psmouse *psmouse);
#else #else
static inline void hgpk_module_init(void)
{
}
static inline int hgpk_detect(struct psmouse *psmouse, bool set_properties) static inline int hgpk_detect(struct psmouse *psmouse, bool set_properties)
{ {
return -ENODEV; return -ENODEV;
......
...@@ -1711,6 +1711,7 @@ static int __init psmouse_init(void) ...@@ -1711,6 +1711,7 @@ static int __init psmouse_init(void)
lifebook_module_init(); lifebook_module_init();
synaptics_module_init(); synaptics_module_init();
hgpk_module_init();
kpsmoused_wq = create_singlethread_workqueue("kpsmoused"); kpsmoused_wq = create_singlethread_workqueue("kpsmoused");
if (!kpsmoused_wq) { if (!kpsmoused_wq) {
......
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/dmi.h> #include <linux/dmi.h>
#include <linux/input.h> #include <linux/input/mt.h>
#include <linux/serio.h> #include <linux/serio.h>
#include <linux/libps2.h> #include <linux/libps2.h>
#include <linux/slab.h> #include <linux/slab.h>
...@@ -279,6 +279,25 @@ static void synaptics_set_rate(struct psmouse *psmouse, unsigned int rate) ...@@ -279,6 +279,25 @@ static void synaptics_set_rate(struct psmouse *psmouse, unsigned int rate)
synaptics_mode_cmd(psmouse, priv->mode); synaptics_mode_cmd(psmouse, priv->mode);
} }
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))
return 0;
if (psmouse_sliced_command(psmouse, SYN_QUE_MODEL))
return -1;
if (ps2_command(&psmouse->ps2dev, &param, PSMOUSE_CMD_SETRATE))
return -1;
/* Advanced gesture mode also sends multi finger data */
priv->capabilities |= BIT(1);
return 0;
}
/***************************************************************************** /*****************************************************************************
* Synaptics pass-through PS/2 port support * Synaptics pass-through PS/2 port support
****************************************************************************/ ****************************************************************************/
...@@ -380,7 +399,9 @@ static void synaptics_pt_create(struct psmouse *psmouse) ...@@ -380,7 +399,9 @@ static void synaptics_pt_create(struct psmouse *psmouse)
* Functions to interpret the absolute mode packets * Functions to interpret the absolute mode packets
****************************************************************************/ ****************************************************************************/
static void synaptics_parse_hw_state(unsigned char buf[], struct synaptics_data *priv, struct synaptics_hw_state *hw) static int synaptics_parse_hw_state(const unsigned char buf[],
struct synaptics_data *priv,
struct synaptics_hw_state *hw)
{ {
memset(hw, 0, sizeof(struct synaptics_hw_state)); memset(hw, 0, sizeof(struct synaptics_hw_state));
...@@ -397,6 +418,14 @@ static void synaptics_parse_hw_state(unsigned char buf[], struct synaptics_data ...@@ -397,6 +418,14 @@ static void synaptics_parse_hw_state(unsigned char buf[], struct synaptics_data
((buf[0] & 0x04) >> 1) | ((buf[0] & 0x04) >> 1) |
((buf[3] & 0x04) >> 2)); ((buf[3] & 0x04) >> 2));
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;
return 1;
}
hw->left = (buf[0] & 0x01) ? 1 : 0; hw->left = (buf[0] & 0x01) ? 1 : 0;
hw->right = (buf[0] & 0x02) ? 1 : 0; hw->right = (buf[0] & 0x02) ? 1 : 0;
...@@ -452,6 +481,36 @@ static void synaptics_parse_hw_state(unsigned char buf[], struct synaptics_data ...@@ -452,6 +481,36 @@ static void synaptics_parse_hw_state(unsigned char buf[], struct synaptics_data
hw->left = (buf[0] & 0x01) ? 1 : 0; hw->left = (buf[0] & 0x01) ? 1 : 0;
hw->right = (buf[0] & 0x02) ? 1 : 0; hw->right = (buf[0] & 0x02) ? 1 : 0;
} }
return 0;
}
static void set_slot(struct input_dev *dev, int slot, bool active, int x, int y)
{
input_mt_slot(dev, 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);
}
}
static void synaptics_report_semi_mt_data(struct input_dev *dev,
const struct synaptics_hw_state *a,
const struct synaptics_hw_state *b,
int num_fingers)
{
if (num_fingers >= 2) {
set_slot(dev, 0, true, min(a->x, b->x), min(a->y, b->y));
set_slot(dev, 1, true, max(a->x, b->x), max(a->y, b->y));
} else if (num_fingers == 1) {
set_slot(dev, 0, true, a->x, a->y);
set_slot(dev, 1, false, 0, 0);
} else {
set_slot(dev, 0, false, 0, 0);
set_slot(dev, 1, false, 0, 0);
}
} }
/* /*
...@@ -466,7 +525,8 @@ static void synaptics_process_packet(struct psmouse *psmouse) ...@@ -466,7 +525,8 @@ static void synaptics_process_packet(struct psmouse *psmouse)
int finger_width; int finger_width;
int i; int i;
synaptics_parse_hw_state(psmouse->packet, priv, &hw); if (synaptics_parse_hw_state(psmouse->packet, priv, &hw))
return;
if (hw.scroll) { if (hw.scroll) {
priv->scroll += hw.scroll; priv->scroll += hw.scroll;
...@@ -488,7 +548,7 @@ static void synaptics_process_packet(struct psmouse *psmouse) ...@@ -488,7 +548,7 @@ static void synaptics_process_packet(struct psmouse *psmouse)
return; return;
} }
if (hw.z > 0) { if (hw.z > 0 && hw.x > 1) {
num_fingers = 1; num_fingers = 1;
finger_width = 5; finger_width = 5;
if (SYN_CAP_EXTENDED(priv->capabilities)) { if (SYN_CAP_EXTENDED(priv->capabilities)) {
...@@ -512,6 +572,9 @@ static void synaptics_process_packet(struct psmouse *psmouse) ...@@ -512,6 +572,9 @@ static void synaptics_process_packet(struct psmouse *psmouse)
finger_width = 0; finger_width = 0;
} }
if (SYN_CAP_ADV_GESTURE(priv->ext_cap_0c))
synaptics_report_semi_mt_data(dev, &hw, &priv->mt, num_fingers);
/* Post events /* Post events
* BTN_TOUCH has to be first as mousedev relies on it when doing * BTN_TOUCH has to be first as mousedev relies on it when doing
* absolute -> relative conversion * absolute -> relative conversion
...@@ -519,7 +582,7 @@ static void synaptics_process_packet(struct psmouse *psmouse) ...@@ -519,7 +582,7 @@ static void synaptics_process_packet(struct psmouse *psmouse)
if (hw.z > 30) input_report_key(dev, BTN_TOUCH, 1); if (hw.z > 30) input_report_key(dev, BTN_TOUCH, 1);
if (hw.z < 25) input_report_key(dev, BTN_TOUCH, 0); if (hw.z < 25) input_report_key(dev, BTN_TOUCH, 0);
if (hw.z > 0) { if (num_fingers > 0) {
input_report_abs(dev, ABS_X, hw.x); 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, YMAX_NOMINAL + YMIN_NOMINAL - hw.y);
} }
...@@ -622,6 +685,8 @@ static void set_input_params(struct input_dev *dev, struct synaptics_data *priv) ...@@ -622,6 +685,8 @@ static void set_input_params(struct input_dev *dev, struct synaptics_data *priv)
{ {
int i; int i;
__set_bit(INPUT_PROP_POINTER, dev->propbit);
__set_bit(EV_ABS, dev->evbit); __set_bit(EV_ABS, dev->evbit);
input_set_abs_params(dev, ABS_X, input_set_abs_params(dev, ABS_X,
XMIN_NOMINAL, priv->x_max ?: XMAX_NOMINAL, 0, 0); XMIN_NOMINAL, priv->x_max ?: XMAX_NOMINAL, 0, 0);
...@@ -629,6 +694,15 @@ static void set_input_params(struct input_dev *dev, struct synaptics_data *priv) ...@@ -629,6 +694,15 @@ static void set_input_params(struct input_dev *dev, struct synaptics_data *priv)
YMIN_NOMINAL, priv->y_max ?: YMAX_NOMINAL, 0, 0); YMIN_NOMINAL, priv->y_max ?: YMAX_NOMINAL, 0, 0);
input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0); input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0);
if (SYN_CAP_ADV_GESTURE(priv->ext_cap_0c)) {
__set_bit(INPUT_PROP_SEMI_MT, dev->propbit);
input_mt_init_slots(dev, 2);
input_set_abs_params(dev, ABS_MT_POSITION_X, XMIN_NOMINAL,
priv->x_max ?: XMAX_NOMINAL, 0, 0);
input_set_abs_params(dev, ABS_MT_POSITION_Y, YMIN_NOMINAL,
priv->y_max ?: YMAX_NOMINAL, 0, 0);
}
if (SYN_CAP_PALMDETECT(priv->capabilities)) if (SYN_CAP_PALMDETECT(priv->capabilities))
input_set_abs_params(dev, ABS_TOOL_WIDTH, 0, 15, 0, 0); input_set_abs_params(dev, ABS_TOOL_WIDTH, 0, 15, 0, 0);
...@@ -663,6 +737,7 @@ static void set_input_params(struct input_dev *dev, struct synaptics_data *priv) ...@@ -663,6 +737,7 @@ static void set_input_params(struct input_dev *dev, struct synaptics_data *priv)
input_abs_set_res(dev, ABS_Y, priv->y_res); input_abs_set_res(dev, ABS_Y, priv->y_res);
if (SYN_CAP_CLICKPAD(priv->ext_cap_0c)) { if (SYN_CAP_CLICKPAD(priv->ext_cap_0c)) {
__set_bit(INPUT_PROP_BUTTONPAD, dev->propbit);
/* Clickpads report only left button */ /* Clickpads report only left button */
__clear_bit(BTN_RIGHT, dev->keybit); __clear_bit(BTN_RIGHT, dev->keybit);
__clear_bit(BTN_MIDDLE, dev->keybit); __clear_bit(BTN_MIDDLE, dev->keybit);
...@@ -702,6 +777,11 @@ static int synaptics_reconnect(struct psmouse *psmouse) ...@@ -702,6 +777,11 @@ static int synaptics_reconnect(struct psmouse *psmouse)
return -1; return -1;
} }
if (synaptics_set_advanced_gesture_mode(psmouse)) {
printk(KERN_ERR "Advanced gesture mode reconnect failed.\n");
return -1;
}
return 0; return 0;
} }
...@@ -744,15 +824,45 @@ static const struct dmi_system_id __initconst toshiba_dmi_table[] = { ...@@ -744,15 +824,45 @@ static const struct dmi_system_id __initconst toshiba_dmi_table[] = {
#endif #endif
}; };
static bool broken_olpc_ec;
static const struct dmi_system_id __initconst olpc_dmi_table[] = {
#if defined(CONFIG_DMI) && defined(CONFIG_OLPC)
{
/* OLPC XO-1 or XO-1.5 */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "OLPC"),
DMI_MATCH(DMI_PRODUCT_NAME, "XO"),
},
},
{ }
#endif
};
void __init synaptics_module_init(void) void __init synaptics_module_init(void)
{ {
impaired_toshiba_kbc = dmi_check_system(toshiba_dmi_table); impaired_toshiba_kbc = dmi_check_system(toshiba_dmi_table);
broken_olpc_ec = dmi_check_system(olpc_dmi_table);
} }
int synaptics_init(struct psmouse *psmouse) int synaptics_init(struct psmouse *psmouse)
{ {
struct synaptics_data *priv; struct synaptics_data *priv;
/*
* The OLPC XO has issues with Synaptics' absolute mode; similarly to
* the HGPK, it quickly degrades and the hardware becomes jumpy and
* overly sensitive. Not only that, but the constant packet spew
* (even at a lowered 40pps rate) overloads the EC such that key
* presses on the keyboard are missed. Given all of that, don't
* even attempt to use Synaptics mode. Relative mode seems to work
* just fine.
*/
if (broken_olpc_ec) {
printk(KERN_INFO "synaptics: OLPC XO detected, not enabling Synaptics protocol.\n");
return -ENODEV;
}
psmouse->private = priv = kzalloc(sizeof(struct synaptics_data), GFP_KERNEL); psmouse->private = priv = kzalloc(sizeof(struct synaptics_data), GFP_KERNEL);
if (!priv) if (!priv)
return -ENOMEM; return -ENOMEM;
...@@ -769,6 +879,11 @@ int synaptics_init(struct psmouse *psmouse) ...@@ -769,6 +879,11 @@ int synaptics_init(struct psmouse *psmouse)
goto init_fail; goto init_fail;
} }
if (synaptics_set_advanced_gesture_mode(psmouse)) {
printk(KERN_ERR "Advanced gesture mode init failed.\n");
goto init_fail;
}
priv->pkt_type = SYN_MODEL_NEWABS(priv->model_id) ? SYN_NEWABS : SYN_OLDABS; 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", printk(KERN_INFO "Synaptics Touchpad, model: %ld, fw: %ld.%ld, id: %#lx, caps: %#lx/%#lx/%#lx\n",
...@@ -802,8 +917,8 @@ int synaptics_init(struct psmouse *psmouse) ...@@ -802,8 +917,8 @@ int synaptics_init(struct psmouse *psmouse)
/* /*
* Toshiba's KBC seems to have trouble handling data from * Toshiba's KBC seems to have trouble handling data from
* Synaptics as full rate, switch to lower rate which is roughly * Synaptics at full rate. Switch to a lower rate (roughly
* thye same as rate of standard PS/2 mouse. * the same rate as a standard PS/2 mouse).
*/ */
if (psmouse->rate >= 80 && impaired_toshiba_kbc) { if (psmouse->rate >= 80 && impaired_toshiba_kbc) {
printk(KERN_INFO "synaptics: Toshiba %s detected, limiting rate to 40pps.\n", printk(KERN_INFO "synaptics: Toshiba %s detected, limiting rate to 40pps.\n",
......
...@@ -54,6 +54,7 @@ ...@@ -54,6 +54,7 @@
#define SYN_CAP_CLICKPAD(ex0c) ((ex0c) & 0x100000) /* 1-button ClickPad */ #define SYN_CAP_CLICKPAD(ex0c) ((ex0c) & 0x100000) /* 1-button ClickPad */
#define SYN_CAP_CLICKPAD2BTN(ex0c) ((ex0c) & 0x000100) /* 2-button ClickPad */ #define SYN_CAP_CLICKPAD2BTN(ex0c) ((ex0c) & 0x000100) /* 2-button ClickPad */
#define SYN_CAP_MAX_DIMENSIONS(ex0c) ((ex0c) & 0x020000) #define SYN_CAP_MAX_DIMENSIONS(ex0c) ((ex0c) & 0x020000)
#define SYN_CAP_ADV_GESTURE(ex0c) ((ex0c) & 0x080000)
/* synaptics modes query bits */ /* synaptics modes query bits */
#define SYN_MODE_ABSOLUTE(m) ((m) & (1 << 7)) #define SYN_MODE_ABSOLUTE(m) ((m) & (1 << 7))
...@@ -113,6 +114,8 @@ struct synaptics_data { ...@@ -113,6 +114,8 @@ struct synaptics_data {
int scroll; int scroll;
struct serio *pt_port; /* Pass-through serio port */ struct serio *pt_port; /* Pass-through serio port */
struct synaptics_hw_state mt; /* current gesture packet */
}; };
void synaptics_module_init(void); void synaptics_module_init(void);
......
...@@ -9,6 +9,8 @@ ...@@ -9,6 +9,8 @@
* the Free Software Foundation. * the Free Software Foundation.
*/ */
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#define MOUSEDEV_MINOR_BASE 32 #define MOUSEDEV_MINOR_BASE 32
#define MOUSEDEV_MINORS 32 #define MOUSEDEV_MINORS 32
#define MOUSEDEV_MIX 31 #define MOUSEDEV_MIX 31
...@@ -977,7 +979,7 @@ static int mousedev_connect(struct input_handler *handler, ...@@ -977,7 +979,7 @@ static int mousedev_connect(struct input_handler *handler,
break; break;
if (minor == MOUSEDEV_MINORS) { if (minor == MOUSEDEV_MINORS) {
printk(KERN_ERR "mousedev: no more free mousedev devices\n"); pr_err("no more free mousedev devices\n");
return -ENFILE; return -ENFILE;
} }
...@@ -1087,13 +1089,13 @@ static int __init mousedev_init(void) ...@@ -1087,13 +1089,13 @@ static int __init mousedev_init(void)
#ifdef CONFIG_INPUT_MOUSEDEV_PSAUX #ifdef CONFIG_INPUT_MOUSEDEV_PSAUX
error = misc_register(&psaux_mouse); error = misc_register(&psaux_mouse);
if (error) if (error)
printk(KERN_WARNING "mice: could not register psaux device, " pr_warning("could not register psaux device, error: %d\n",
"error: %d\n", error); error);
else else
psaux_registered = 1; psaux_registered = 1;
#endif #endif
printk(KERN_INFO "mice: PS/2 mouse device common for all mice\n"); pr_info("PS/2 mouse device common for all mice\n");
return 0; return 0;
} }
......
...@@ -172,6 +172,5 @@ static void __exit ams_delta_serio_exit(void) ...@@ -172,6 +172,5 @@ static void __exit ams_delta_serio_exit(void)
free_irq(OMAP_GPIO_IRQ(AMS_DELTA_GPIO_PIN_KEYBRD_CLK), 0); free_irq(OMAP_GPIO_IRQ(AMS_DELTA_GPIO_PIN_KEYBRD_CLK), 0);
gpio_free(AMS_DELTA_GPIO_PIN_KEYBRD_CLK); gpio_free(AMS_DELTA_GPIO_PIN_KEYBRD_CLK);
gpio_free(AMS_DELTA_GPIO_PIN_KEYBRD_DATA); gpio_free(AMS_DELTA_GPIO_PIN_KEYBRD_DATA);
kfree(ams_delta_serio);
} }
module_exit(ams_delta_serio_exit); module_exit(ams_delta_serio_exit);
...@@ -191,6 +191,9 @@ static int __devinit ct82c710_probe(struct platform_device *dev) ...@@ -191,6 +191,9 @@ static int __devinit ct82c710_probe(struct platform_device *dev)
serio_register_port(ct82c710_port); serio_register_port(ct82c710_port);
printk(KERN_INFO "serio: C&T 82c710 mouse port at %#llx irq %d\n",
(unsigned long long)CT82C710_DATA, CT82C710_IRQ);
return 0; return 0;
} }
...@@ -237,11 +240,6 @@ static int __init ct82c710_init(void) ...@@ -237,11 +240,6 @@ static int __init ct82c710_init(void)
if (error) if (error)
goto err_free_device; goto err_free_device;
serio_register_port(ct82c710_port);
printk(KERN_INFO "serio: C&T 82c710 mouse port at %#llx irq %d\n",
(unsigned long long)CT82C710_DATA, CT82C710_IRQ);
return 0; return 0;
err_free_device: err_free_device:
......
...@@ -932,6 +932,11 @@ int hil_mlc_register(hil_mlc *mlc) ...@@ -932,6 +932,11 @@ int hil_mlc_register(hil_mlc *mlc)
hil_mlc_copy_di_scratch(mlc, i); hil_mlc_copy_di_scratch(mlc, i);
mlc_serio = kzalloc(sizeof(*mlc_serio), GFP_KERNEL); mlc_serio = kzalloc(sizeof(*mlc_serio), GFP_KERNEL);
mlc->serio[i] = mlc_serio; mlc->serio[i] = mlc_serio;
if (!mlc->serio[i]) {
for (; i >= 0; i--)
kfree(mlc->serio[i]);
return -ENOMEM;
}
snprintf(mlc_serio->name, sizeof(mlc_serio->name)-1, "HIL_SERIO%d", i); snprintf(mlc_serio->name, sizeof(mlc_serio->name)-1, "HIL_SERIO%d", i);
snprintf(mlc_serio->phys, sizeof(mlc_serio->phys)-1, "HIL%d", i); snprintf(mlc_serio->phys, sizeof(mlc_serio->phys)-1, "HIL%d", i);
mlc_serio->id = hil_mlc_serio_id; mlc_serio->id = hil_mlc_serio_id;
......
...@@ -305,6 +305,7 @@ static void hp_sdc_mlc_out(hil_mlc *mlc) ...@@ -305,6 +305,7 @@ static void hp_sdc_mlc_out(hil_mlc *mlc)
static int __init hp_sdc_mlc_init(void) static int __init hp_sdc_mlc_init(void)
{ {
hil_mlc *mlc = &hp_sdc_mlc; hil_mlc *mlc = &hp_sdc_mlc;
int err;
#ifdef __mc68000__ #ifdef __mc68000__
if (!MACH_IS_HP300) if (!MACH_IS_HP300)
...@@ -323,22 +324,21 @@ static int __init hp_sdc_mlc_init(void) ...@@ -323,22 +324,21 @@ static int __init hp_sdc_mlc_init(void)
mlc->out = &hp_sdc_mlc_out; mlc->out = &hp_sdc_mlc_out;
mlc->priv = &hp_sdc_mlc_priv; mlc->priv = &hp_sdc_mlc_priv;
if (hil_mlc_register(mlc)) { err = hil_mlc_register(mlc);
if (err) {
printk(KERN_WARNING PREFIX "Failed to register MLC structure with hil_mlc\n"); printk(KERN_WARNING PREFIX "Failed to register MLC structure with hil_mlc\n");
goto err0; return err;
} }
if (hp_sdc_request_hil_irq(&hp_sdc_mlc_isr)) { if (hp_sdc_request_hil_irq(&hp_sdc_mlc_isr)) {
printk(KERN_WARNING PREFIX "Request for raw HIL ISR hook denied\n"); printk(KERN_WARNING PREFIX "Request for raw HIL ISR hook denied\n");
goto err1; if (hil_mlc_unregister(mlc))
printk(KERN_ERR PREFIX "Failed to unregister MLC structure with hil_mlc.\n"
"This is bad. Could cause an oops.\n");
return -EBUSY;
} }
return 0; return 0;
err1:
if (hil_mlc_unregister(mlc))
printk(KERN_ERR PREFIX "Failed to unregister MLC structure with hil_mlc.\n"
"This is bad. Could cause an oops.\n");
err0:
return -EBUSY;
} }
static void __exit hp_sdc_mlc_exit(void) static void __exit hp_sdc_mlc_exit(void)
......
...@@ -552,6 +552,13 @@ static const struct dmi_system_id __initconst i8042_dmi_laptop_table[] = { ...@@ -552,6 +552,13 @@ static const struct dmi_system_id __initconst i8042_dmi_laptop_table[] = {
* have turned up in 2007 that also need this again. * have turned up in 2007 that also need this again.
*/ */
static const struct dmi_system_id __initconst i8042_dmi_dritek_table[] = { static const struct dmi_system_id __initconst i8042_dmi_dritek_table[] = {
{
/* Acer Aspire 5100 */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5100"),
},
},
{ {
/* Acer Aspire 5610 */ /* Acer Aspire 5610 */
.matches = { .matches = {
...@@ -752,7 +759,7 @@ static int __init i8042_pnp_init(void) ...@@ -752,7 +759,7 @@ static int __init i8042_pnp_init(void)
#endif #endif
if (i8042_nopnp) { if (i8042_nopnp) {
printk(KERN_INFO "i8042: PNP detection disabled\n"); pr_info("PNP detection disabled\n");
return 0; return 0;
} }
...@@ -769,7 +776,7 @@ static int __init i8042_pnp_init(void) ...@@ -769,7 +776,7 @@ static int __init i8042_pnp_init(void)
#if defined(__ia64__) #if defined(__ia64__)
return -ENODEV; return -ENODEV;
#else #else
printk(KERN_INFO "PNP: No PS/2 controller found. Probing ports directly.\n"); pr_info("PNP: No PS/2 controller found. Probing ports directly.\n");
return 0; return 0;
#endif #endif
} }
...@@ -781,7 +788,7 @@ static int __init i8042_pnp_init(void) ...@@ -781,7 +788,7 @@ static int __init i8042_pnp_init(void)
snprintf(aux_irq_str, sizeof(aux_irq_str), snprintf(aux_irq_str, sizeof(aux_irq_str),
"%d", i8042_pnp_aux_irq); "%d", i8042_pnp_aux_irq);
printk(KERN_INFO "PNP: PS/2 Controller [%s%s%s] at %#x,%#x irq %s%s%s\n", pr_info("PNP: PS/2 Controller [%s%s%s] at %#x,%#x irq %s%s%s\n",
i8042_pnp_kbd_name, (i8042_pnp_kbd_devices && i8042_pnp_aux_devices) ? "," : "", i8042_pnp_kbd_name, (i8042_pnp_kbd_devices && i8042_pnp_aux_devices) ? "," : "",
i8042_pnp_aux_name, i8042_pnp_aux_name,
i8042_pnp_data_reg, i8042_pnp_command_reg, i8042_pnp_data_reg, i8042_pnp_command_reg,
...@@ -798,9 +805,7 @@ static int __init i8042_pnp_init(void) ...@@ -798,9 +805,7 @@ static int __init i8042_pnp_init(void)
if (((i8042_pnp_data_reg & ~0xf) == (i8042_data_reg & ~0xf) && if (((i8042_pnp_data_reg & ~0xf) == (i8042_data_reg & ~0xf) &&
i8042_pnp_data_reg != i8042_data_reg) || i8042_pnp_data_reg != i8042_data_reg) ||
!i8042_pnp_data_reg) { !i8042_pnp_data_reg) {
printk(KERN_WARNING pr_warn("PNP: PS/2 controller has invalid data port %#x; using default %#x\n",
"PNP: PS/2 controller has invalid data port %#x; "
"using default %#x\n",
i8042_pnp_data_reg, i8042_data_reg); i8042_pnp_data_reg, i8042_data_reg);
i8042_pnp_data_reg = i8042_data_reg; i8042_pnp_data_reg = i8042_data_reg;
pnp_data_busted = true; pnp_data_busted = true;
...@@ -809,33 +814,27 @@ static int __init i8042_pnp_init(void) ...@@ -809,33 +814,27 @@ static int __init i8042_pnp_init(void)
if (((i8042_pnp_command_reg & ~0xf) == (i8042_command_reg & ~0xf) && if (((i8042_pnp_command_reg & ~0xf) == (i8042_command_reg & ~0xf) &&
i8042_pnp_command_reg != i8042_command_reg) || i8042_pnp_command_reg != i8042_command_reg) ||
!i8042_pnp_command_reg) { !i8042_pnp_command_reg) {
printk(KERN_WARNING pr_warn("PNP: PS/2 controller has invalid command port %#x; using default %#x\n",
"PNP: PS/2 controller has invalid command port %#x; "
"using default %#x\n",
i8042_pnp_command_reg, i8042_command_reg); i8042_pnp_command_reg, i8042_command_reg);
i8042_pnp_command_reg = i8042_command_reg; i8042_pnp_command_reg = i8042_command_reg;
pnp_data_busted = true; pnp_data_busted = true;
} }
if (!i8042_nokbd && !i8042_pnp_kbd_irq) { if (!i8042_nokbd && !i8042_pnp_kbd_irq) {
printk(KERN_WARNING pr_warn("PNP: PS/2 controller doesn't have KBD irq; using default %d\n",
"PNP: PS/2 controller doesn't have KBD irq; " i8042_kbd_irq);
"using default %d\n", i8042_kbd_irq);
i8042_pnp_kbd_irq = i8042_kbd_irq; i8042_pnp_kbd_irq = i8042_kbd_irq;
pnp_data_busted = true; pnp_data_busted = true;
} }
if (!i8042_noaux && !i8042_pnp_aux_irq) { if (!i8042_noaux && !i8042_pnp_aux_irq) {
if (!pnp_data_busted && i8042_pnp_kbd_irq) { if (!pnp_data_busted && i8042_pnp_kbd_irq) {
printk(KERN_WARNING pr_warn("PNP: PS/2 appears to have AUX port disabled, "
"PNP: PS/2 appears to have AUX port disabled, " "if this is incorrect please boot with i8042.nopnp\n");
"if this is incorrect please boot with "
"i8042.nopnp\n");
i8042_noaux = true; i8042_noaux = true;
} else { } else {
printk(KERN_WARNING pr_warn("PNP: PS/2 controller doesn't have AUX irq; using default %d\n",
"PNP: PS/2 controller doesn't have AUX irq; " i8042_aux_irq);
"using default %d\n", i8042_aux_irq);
i8042_pnp_aux_irq = i8042_aux_irq; i8042_pnp_aux_irq = i8042_aux_irq;
} }
} }
......
...@@ -10,6 +10,8 @@ ...@@ -10,6 +10,8 @@
* the Free Software Foundation. * the Free Software Foundation.
*/ */
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/types.h> #include <linux/types.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/module.h> #include <linux/module.h>
...@@ -225,8 +227,8 @@ static int i8042_flush(void) ...@@ -225,8 +227,8 @@ static int i8042_flush(void)
udelay(50); udelay(50);
data = i8042_read_data(); data = i8042_read_data();
i++; i++;
dbg("%02x <- i8042 (flush, %s)", data, dbg("%02x <- i8042 (flush, %s)\n",
str & I8042_STR_AUXDATA ? "aux" : "kbd"); data, str & I8042_STR_AUXDATA ? "aux" : "kbd");
} }
spin_unlock_irqrestore(&i8042_lock, flags); spin_unlock_irqrestore(&i8042_lock, flags);
...@@ -253,32 +255,32 @@ static int __i8042_command(unsigned char *param, int command) ...@@ -253,32 +255,32 @@ static int __i8042_command(unsigned char *param, int command)
if (error) if (error)
return error; return error;
dbg("%02x -> i8042 (command)", command & 0xff); dbg("%02x -> i8042 (command)\n", command & 0xff);
i8042_write_command(command & 0xff); i8042_write_command(command & 0xff);
for (i = 0; i < ((command >> 12) & 0xf); i++) { for (i = 0; i < ((command >> 12) & 0xf); i++) {
error = i8042_wait_write(); error = i8042_wait_write();
if (error) if (error)
return error; return error;
dbg("%02x -> i8042 (parameter)", param[i]); dbg("%02x -> i8042 (parameter)\n", param[i]);
i8042_write_data(param[i]); i8042_write_data(param[i]);
} }
for (i = 0; i < ((command >> 8) & 0xf); i++) { for (i = 0; i < ((command >> 8) & 0xf); i++) {
error = i8042_wait_read(); error = i8042_wait_read();
if (error) { if (error) {
dbg(" -- i8042 (timeout)"); dbg(" -- i8042 (timeout)\n");
return error; return error;
} }
if (command == I8042_CMD_AUX_LOOP && if (command == I8042_CMD_AUX_LOOP &&
!(i8042_read_status() & I8042_STR_AUXDATA)) { !(i8042_read_status() & I8042_STR_AUXDATA)) {
dbg(" -- i8042 (auxerr)"); dbg(" -- i8042 (auxerr)\n");
return -1; return -1;
} }
param[i] = i8042_read_data(); param[i] = i8042_read_data();
dbg("%02x <- i8042 (return)", param[i]); dbg("%02x <- i8042 (return)\n", param[i]);
} }
return 0; return 0;
...@@ -309,7 +311,7 @@ static int i8042_kbd_write(struct serio *port, unsigned char c) ...@@ -309,7 +311,7 @@ static int i8042_kbd_write(struct serio *port, unsigned char c)
spin_lock_irqsave(&i8042_lock, flags); spin_lock_irqsave(&i8042_lock, flags);
if (!(retval = i8042_wait_write())) { if (!(retval = i8042_wait_write())) {
dbg("%02x -> i8042 (kbd-data)", c); dbg("%02x -> i8042 (kbd-data)\n", c);
i8042_write_data(c); i8042_write_data(c);
} }
...@@ -355,17 +357,14 @@ static void i8042_port_close(struct serio *serio) ...@@ -355,17 +357,14 @@ static void i8042_port_close(struct serio *serio)
i8042_ctr &= ~irq_bit; i8042_ctr &= ~irq_bit;
if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR))
printk(KERN_WARNING pr_warn("Can't write CTR while closing %s port\n", port_name);
"i8042.c: Can't write CTR while closing %s port.\n",
port_name);
udelay(50); udelay(50);
i8042_ctr &= ~disable_bit; i8042_ctr &= ~disable_bit;
i8042_ctr |= irq_bit; i8042_ctr |= irq_bit;
if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR))
printk(KERN_ERR "i8042.c: Can't reactivate %s port.\n", pr_err("Can't reactivate %s port\n", port_name);
port_name);
/* /*
* See if there is any data appeared while we were messing with * See if there is any data appeared while we were messing with
...@@ -456,7 +455,8 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id) ...@@ -456,7 +455,8 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id)
str = i8042_read_status(); str = i8042_read_status();
if (unlikely(~str & I8042_STR_OBF)) { if (unlikely(~str & I8042_STR_OBF)) {
spin_unlock_irqrestore(&i8042_lock, flags); spin_unlock_irqrestore(&i8042_lock, flags);
if (irq) dbg("Interrupt %d, without any data", irq); if (irq)
dbg("Interrupt %d, without any data\n", irq);
ret = 0; ret = 0;
goto out; goto out;
} }
...@@ -469,7 +469,8 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id) ...@@ -469,7 +469,8 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id)
dfl = 0; dfl = 0;
if (str & I8042_STR_MUXERR) { if (str & I8042_STR_MUXERR) {
dbg("MUX error, status is %02x, data is %02x", str, data); dbg("MUX error, status is %02x, data is %02x\n",
str, data);
/* /*
* When MUXERR condition is signalled the data register can only contain * When MUXERR condition is signalled the data register can only contain
* 0xfd, 0xfe or 0xff if implementation follows the spec. Unfortunately * 0xfd, 0xfe or 0xff if implementation follows the spec. Unfortunately
...@@ -512,7 +513,7 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id) ...@@ -512,7 +513,7 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id)
port = &i8042_ports[port_no]; port = &i8042_ports[port_no];
serio = port->exists ? port->serio : NULL; serio = port->exists ? port->serio : NULL;
dbg("%02x <- i8042 (interrupt, %d, %d%s%s)", dbg("%02x <- i8042 (interrupt, %d, %d%s%s)\n",
data, port_no, irq, data, port_no, irq,
dfl & SERIO_PARITY ? ", bad parity" : "", dfl & SERIO_PARITY ? ", bad parity" : "",
dfl & SERIO_TIMEOUT ? ", timeout" : ""); dfl & SERIO_TIMEOUT ? ", timeout" : "");
...@@ -540,7 +541,7 @@ static int i8042_enable_kbd_port(void) ...@@ -540,7 +541,7 @@ static int i8042_enable_kbd_port(void)
if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
i8042_ctr &= ~I8042_CTR_KBDINT; i8042_ctr &= ~I8042_CTR_KBDINT;
i8042_ctr |= I8042_CTR_KBDDIS; i8042_ctr |= I8042_CTR_KBDDIS;
printk(KERN_ERR "i8042.c: Failed to enable KBD port.\n"); pr_err("Failed to enable KBD port\n");
return -EIO; return -EIO;
} }
...@@ -559,7 +560,7 @@ static int i8042_enable_aux_port(void) ...@@ -559,7 +560,7 @@ static int i8042_enable_aux_port(void)
if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
i8042_ctr &= ~I8042_CTR_AUXINT; i8042_ctr &= ~I8042_CTR_AUXINT;
i8042_ctr |= I8042_CTR_AUXDIS; i8042_ctr |= I8042_CTR_AUXDIS;
printk(KERN_ERR "i8042.c: Failed to enable AUX port.\n"); pr_err("Failed to enable AUX port\n");
return -EIO; return -EIO;
} }
...@@ -641,7 +642,7 @@ static int __init i8042_check_mux(void) ...@@ -641,7 +642,7 @@ static int __init i8042_check_mux(void)
if (i8042_set_mux_mode(true, &mux_version)) if (i8042_set_mux_mode(true, &mux_version))
return -1; return -1;
printk(KERN_INFO "i8042.c: Detected active multiplexing controller, rev %d.%d.\n", pr_info("Detected active multiplexing controller, rev %d.%d\n",
(mux_version >> 4) & 0xf, mux_version & 0xf); (mux_version >> 4) & 0xf, mux_version & 0xf);
/* /*
...@@ -651,7 +652,7 @@ static int __init i8042_check_mux(void) ...@@ -651,7 +652,7 @@ static int __init i8042_check_mux(void)
i8042_ctr &= ~I8042_CTR_AUXINT; i8042_ctr &= ~I8042_CTR_AUXINT;
if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
printk(KERN_ERR "i8042.c: Failed to disable AUX port, can't use MUX.\n"); pr_err("Failed to disable AUX port, can't use MUX\n");
return -EIO; return -EIO;
} }
...@@ -676,8 +677,8 @@ static irqreturn_t __init i8042_aux_test_irq(int irq, void *dev_id) ...@@ -676,8 +677,8 @@ static irqreturn_t __init i8042_aux_test_irq(int irq, void *dev_id)
str = i8042_read_status(); str = i8042_read_status();
if (str & I8042_STR_OBF) { if (str & I8042_STR_OBF) {
data = i8042_read_data(); data = i8042_read_data();
dbg("%02x <- i8042 (aux_test_irq, %s)", dbg("%02x <- i8042 (aux_test_irq, %s)\n",
data, str & I8042_STR_AUXDATA ? "aux" : "kbd"); data, str & I8042_STR_AUXDATA ? "aux" : "kbd");
if (i8042_irq_being_tested && if (i8042_irq_being_tested &&
data == 0xa5 && (str & I8042_STR_AUXDATA)) data == 0xa5 && (str & I8042_STR_AUXDATA))
complete(&i8042_aux_irq_delivered); complete(&i8042_aux_irq_delivered);
...@@ -770,8 +771,8 @@ static int __init i8042_check_aux(void) ...@@ -770,8 +771,8 @@ static int __init i8042_check_aux(void)
*/ */
if (i8042_toggle_aux(false)) { if (i8042_toggle_aux(false)) {
printk(KERN_WARNING "Failed to disable AUX port, but continuing anyway... Is this a SiS?\n"); pr_warn("Failed to disable AUX port, but continuing anyway... Is this a SiS?\n");
printk(KERN_WARNING "If AUX port is really absent please use the 'i8042.noaux' option.\n"); pr_warn("If AUX port is really absent please use the 'i8042.noaux' option\n");
} }
if (i8042_toggle_aux(true)) if (i8042_toggle_aux(true))
...@@ -819,7 +820,7 @@ static int __init i8042_check_aux(void) ...@@ -819,7 +820,7 @@ static int __init i8042_check_aux(void)
* AUX IRQ was never delivered so we need to flush the controller to * AUX IRQ was never delivered so we need to flush the controller to
* get rid of the byte we put there; otherwise keyboard may not work. * get rid of the byte we put there; otherwise keyboard may not work.
*/ */
dbg(" -- i8042 (aux irq test timeout)"); dbg(" -- i8042 (aux irq test timeout)\n");
i8042_flush(); i8042_flush();
retval = -1; retval = -1;
} }
...@@ -845,7 +846,7 @@ static int __init i8042_check_aux(void) ...@@ -845,7 +846,7 @@ static int __init i8042_check_aux(void)
static int i8042_controller_check(void) static int i8042_controller_check(void)
{ {
if (i8042_flush() == I8042_BUFFER_SIZE) { if (i8042_flush() == I8042_BUFFER_SIZE) {
printk(KERN_ERR "i8042.c: No controller found.\n"); pr_err("No controller found\n");
return -ENODEV; return -ENODEV;
} }
...@@ -864,15 +865,15 @@ static int i8042_controller_selftest(void) ...@@ -864,15 +865,15 @@ static int i8042_controller_selftest(void)
do { do {
if (i8042_command(&param, I8042_CMD_CTL_TEST)) { if (i8042_command(&param, I8042_CMD_CTL_TEST)) {
printk(KERN_ERR "i8042.c: i8042 controller self test timeout.\n"); pr_err("i8042 controller self test timeout\n");
return -ENODEV; return -ENODEV;
} }
if (param == I8042_RET_CTL_TEST) if (param == I8042_RET_CTL_TEST)
return 0; return 0;
printk(KERN_ERR "i8042.c: i8042 controller selftest failed. (%#x != %#x)\n", pr_err("i8042 controller selftest failed. (%#x != %#x)\n",
param, I8042_RET_CTL_TEST); param, I8042_RET_CTL_TEST);
msleep(50); msleep(50);
} while (i++ < 5); } while (i++ < 5);
...@@ -883,8 +884,7 @@ static int i8042_controller_selftest(void) ...@@ -883,8 +884,7 @@ static int i8042_controller_selftest(void)
* and user will still get a working keyboard. This is especially * and user will still get a working keyboard. This is especially
* important on netbooks. On other arches we trust hardware more. * important on netbooks. On other arches we trust hardware more.
*/ */
printk(KERN_INFO pr_info("giving up on controller selftest, continuing anyway...\n");
"i8042: giving up on controller selftest, continuing anyway...\n");
return 0; return 0;
#else #else
return -EIO; return -EIO;
...@@ -909,8 +909,7 @@ static int i8042_controller_init(void) ...@@ -909,8 +909,7 @@ static int i8042_controller_init(void)
do { do {
if (n >= 10) { if (n >= 10) {
printk(KERN_ERR pr_err("Unable to get stable CTR read\n");
"i8042.c: Unable to get stable CTR read.\n");
return -EIO; return -EIO;
} }
...@@ -918,8 +917,7 @@ static int i8042_controller_init(void) ...@@ -918,8 +917,7 @@ static int i8042_controller_init(void)
udelay(50); udelay(50);
if (i8042_command(&ctr[n++ % 2], I8042_CMD_CTL_RCTR)) { if (i8042_command(&ctr[n++ % 2], I8042_CMD_CTL_RCTR)) {
printk(KERN_ERR pr_err("Can't read CTR while initializing i8042\n");
"i8042.c: Can't read CTR while initializing i8042.\n");
return -EIO; return -EIO;
} }
...@@ -943,7 +941,7 @@ static int i8042_controller_init(void) ...@@ -943,7 +941,7 @@ static int i8042_controller_init(void)
if (i8042_unlock) if (i8042_unlock)
i8042_ctr |= I8042_CTR_IGNKEYLOCK; i8042_ctr |= I8042_CTR_IGNKEYLOCK;
else else
printk(KERN_WARNING "i8042.c: Warning: Keylock active.\n"); pr_warn("Warning: Keylock active\n");
} }
spin_unlock_irqrestore(&i8042_lock, flags); spin_unlock_irqrestore(&i8042_lock, flags);
...@@ -970,7 +968,7 @@ static int i8042_controller_init(void) ...@@ -970,7 +968,7 @@ static int i8042_controller_init(void)
*/ */
if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
printk(KERN_ERR "i8042.c: Can't write CTR while initializing i8042.\n"); pr_err("Can't write CTR while initializing i8042\n");
return -EIO; return -EIO;
} }
...@@ -1000,7 +998,7 @@ static void i8042_controller_reset(void) ...@@ -1000,7 +998,7 @@ static void i8042_controller_reset(void)
i8042_ctr &= ~(I8042_CTR_KBDINT | I8042_CTR_AUXINT); i8042_ctr &= ~(I8042_CTR_KBDINT | I8042_CTR_AUXINT);
if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR))
printk(KERN_WARNING "i8042.c: Can't write CTR while resetting.\n"); pr_warn("Can't write CTR while resetting\n");
/* /*
* Disable MUX mode if present. * Disable MUX mode if present.
...@@ -1021,7 +1019,7 @@ static void i8042_controller_reset(void) ...@@ -1021,7 +1019,7 @@ static void i8042_controller_reset(void)
*/ */
if (i8042_command(&i8042_initial_ctr, I8042_CMD_CTL_WCTR)) if (i8042_command(&i8042_initial_ctr, I8042_CMD_CTL_WCTR))
printk(KERN_WARNING "i8042.c: Can't restore CTR.\n"); pr_warn("Can't restore CTR\n");
} }
...@@ -1045,14 +1043,14 @@ static long i8042_panic_blink(int state) ...@@ -1045,14 +1043,14 @@ static long i8042_panic_blink(int state)
led = (state) ? 0x01 | 0x04 : 0; led = (state) ? 0x01 | 0x04 : 0;
while (i8042_read_status() & I8042_STR_IBF) while (i8042_read_status() & I8042_STR_IBF)
DELAY; DELAY;
dbg("%02x -> i8042 (panic blink)", 0xed); dbg("%02x -> i8042 (panic blink)\n", 0xed);
i8042_suppress_kbd_ack = 2; i8042_suppress_kbd_ack = 2;
i8042_write_data(0xed); /* set leds */ i8042_write_data(0xed); /* set leds */
DELAY; DELAY;
while (i8042_read_status() & I8042_STR_IBF) while (i8042_read_status() & I8042_STR_IBF)
DELAY; DELAY;
DELAY; DELAY;
dbg("%02x -> i8042 (panic blink)", led); dbg("%02x -> i8042 (panic blink)\n", led);
i8042_write_data(led); i8042_write_data(led);
DELAY; DELAY;
return delay; return delay;
...@@ -1068,9 +1066,7 @@ static void i8042_dritek_enable(void) ...@@ -1068,9 +1066,7 @@ static void i8042_dritek_enable(void)
error = i8042_command(&param, 0x1059); error = i8042_command(&param, 0x1059);
if (error) if (error)
printk(KERN_WARNING pr_warn("Failed to enable DRITEK extension: %d\n", error);
"Failed to enable DRITEK extension: %d\n",
error);
} }
#endif #endif
...@@ -1105,10 +1101,10 @@ static int i8042_controller_resume(bool force_reset) ...@@ -1105,10 +1101,10 @@ static int i8042_controller_resume(bool force_reset)
i8042_ctr |= I8042_CTR_AUXDIS | I8042_CTR_KBDDIS; i8042_ctr |= I8042_CTR_AUXDIS | I8042_CTR_KBDDIS;
i8042_ctr &= ~(I8042_CTR_AUXINT | I8042_CTR_KBDINT); i8042_ctr &= ~(I8042_CTR_AUXINT | I8042_CTR_KBDINT);
if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
printk(KERN_WARNING "i8042: Can't write CTR to resume, retrying...\n"); pr_warn("Can't write CTR to resume, retrying...\n");
msleep(50); msleep(50);
if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
printk(KERN_ERR "i8042: CTR write retry failed\n"); pr_err("CTR write retry failed\n");
return -EIO; return -EIO;
} }
} }
...@@ -1121,9 +1117,7 @@ static int i8042_controller_resume(bool force_reset) ...@@ -1121,9 +1117,7 @@ static int i8042_controller_resume(bool force_reset)
if (i8042_mux_present) { if (i8042_mux_present) {
if (i8042_set_mux_mode(true, NULL) || i8042_enable_mux_ports()) if (i8042_set_mux_mode(true, NULL) || i8042_enable_mux_ports())
printk(KERN_WARNING pr_warn("failed to resume active multiplexor, mouse won't work\n");
"i8042: failed to resume active multiplexor, "
"mouse won't work.\n");
} else if (i8042_ports[I8042_AUX_PORT_NO].serio) } else if (i8042_ports[I8042_AUX_PORT_NO].serio)
i8042_enable_aux_port(); i8042_enable_aux_port();
......
...@@ -89,15 +89,19 @@ ...@@ -89,15 +89,19 @@
#ifdef DEBUG #ifdef DEBUG
static unsigned long i8042_start_time; static unsigned long i8042_start_time;
#define dbg_init() do { i8042_start_time = jiffies; } while (0) #define dbg_init() do { i8042_start_time = jiffies; } while (0)
#define dbg(format, arg...) \ #define dbg(format, arg...) \
do { \ do { \
if (i8042_debug) \ if (i8042_debug) \
printk(KERN_DEBUG __FILE__ ": " format " [%d]\n" , \ printk(KERN_DEBUG KBUILD_MODNAME ": [%d] " format, \
## arg, (int) (jiffies - i8042_start_time)); \ (int) (jiffies - i8042_start_time), ##arg); \
} while (0) } while (0)
#else #else
#define dbg_init() do { } while (0) #define dbg_init() do { } while (0)
#define dbg(format, arg...) do {} while (0) #define dbg(format, arg...) \
do { \
if (0) \
printk(KERN_DEBUG pr_fmt(format), ##arg); \
} while (0)
#endif #endif
#endif /* _I8042_H */ #endif /* _I8042_H */
...@@ -207,7 +207,7 @@ static int ps2mult_connect(struct serio *serio, struct serio_driver *drv) ...@@ -207,7 +207,7 @@ static int ps2mult_connect(struct serio *serio, struct serio_driver *drv)
err_out: err_out:
while (--i >= 0) while (--i >= 0)
kfree(psm->ports[i].serio); kfree(psm->ports[i].serio);
kfree(serio); kfree(psm);
return error; return error;
} }
......
...@@ -32,10 +32,9 @@ ...@@ -32,10 +32,9 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/serio.h> #include <linux/serio.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/wait.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/kthread.h> #include <linux/workqueue.h>
#include <linux/mutex.h> #include <linux/mutex.h>
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
...@@ -44,7 +43,7 @@ MODULE_LICENSE("GPL"); ...@@ -44,7 +43,7 @@ MODULE_LICENSE("GPL");
/* /*
* serio_mutex protects entire serio subsystem and is taken every time * serio_mutex protects entire serio subsystem and is taken every time
* serio port or driver registrered or unregistered. * serio port or driver registered or unregistered.
*/ */
static DEFINE_MUTEX(serio_mutex); static DEFINE_MUTEX(serio_mutex);
...@@ -165,58 +164,22 @@ struct serio_event { ...@@ -165,58 +164,22 @@ struct serio_event {
static DEFINE_SPINLOCK(serio_event_lock); /* protects serio_event_list */ static DEFINE_SPINLOCK(serio_event_lock); /* protects serio_event_list */
static LIST_HEAD(serio_event_list); static LIST_HEAD(serio_event_list);
static DECLARE_WAIT_QUEUE_HEAD(serio_wait);
static struct task_struct *serio_task;
static int serio_queue_event(void *object, struct module *owner, static struct serio_event *serio_get_event(void)
enum serio_event_type event_type)
{ {
struct serio_event *event = NULL;
unsigned long flags; unsigned long flags;
struct serio_event *event;
int retval = 0;
spin_lock_irqsave(&serio_event_lock, flags); spin_lock_irqsave(&serio_event_lock, flags);
/* if (!list_empty(&serio_event_list)) {
* Scan event list for the other events for the same serio port, event = list_first_entry(&serio_event_list,
* starting with the most recent one. If event is the same we struct serio_event, node);
* do not need add new one. If event is of different type we list_del_init(&event->node);
* need to add this event and should not look further because
* we need to preseve sequence of distinct events.
*/
list_for_each_entry_reverse(event, &serio_event_list, node) {
if (event->object == object) {
if (event->type == event_type)
goto out;
break;
}
}
event = kmalloc(sizeof(struct serio_event), GFP_ATOMIC);
if (!event) {
pr_err("Not enough memory to queue event %d\n", event_type);
retval = -ENOMEM;
goto out;
}
if (!try_module_get(owner)) {
pr_warning("Can't get module reference, dropping event %d\n",
event_type);
kfree(event);
retval = -EINVAL;
goto out;
} }
event->type = event_type;
event->object = object;
event->owner = owner;
list_add_tail(&event->node, &serio_event_list);
wake_up(&serio_wait);
out:
spin_unlock_irqrestore(&serio_event_lock, flags); spin_unlock_irqrestore(&serio_event_lock, flags);
return retval; return event;
} }
static void serio_free_event(struct serio_event *event) static void serio_free_event(struct serio_event *event)
...@@ -250,25 +213,7 @@ static void serio_remove_duplicate_events(struct serio_event *event) ...@@ -250,25 +213,7 @@ static void serio_remove_duplicate_events(struct serio_event *event)
spin_unlock_irqrestore(&serio_event_lock, flags); spin_unlock_irqrestore(&serio_event_lock, flags);
} }
static void serio_handle_event(struct work_struct *work)
static struct serio_event *serio_get_event(void)
{
struct serio_event *event = NULL;
unsigned long flags;
spin_lock_irqsave(&serio_event_lock, flags);
if (!list_empty(&serio_event_list)) {
event = list_first_entry(&serio_event_list,
struct serio_event, node);
list_del_init(&event->node);
}
spin_unlock_irqrestore(&serio_event_lock, flags);
return event;
}
static void serio_handle_event(void)
{ {
struct serio_event *event; struct serio_event *event;
...@@ -307,6 +252,59 @@ static void serio_handle_event(void) ...@@ -307,6 +252,59 @@ static void serio_handle_event(void)
mutex_unlock(&serio_mutex); mutex_unlock(&serio_mutex);
} }
static DECLARE_WORK(serio_event_work, serio_handle_event);
static int serio_queue_event(void *object, struct module *owner,
enum serio_event_type event_type)
{
unsigned long flags;
struct serio_event *event;
int retval = 0;
spin_lock_irqsave(&serio_event_lock, flags);
/*
* Scan event list for the other events for the same serio port,
* starting with the most recent one. If event is the same we
* do not need add new one. If event is of different type we
* need to add this event and should not look further because
* we need to preseve sequence of distinct events.
*/
list_for_each_entry_reverse(event, &serio_event_list, node) {
if (event->object == object) {
if (event->type == event_type)
goto out;
break;
}
}
event = kmalloc(sizeof(struct serio_event), GFP_ATOMIC);
if (!event) {
pr_err("Not enough memory to queue event %d\n", event_type);
retval = -ENOMEM;
goto out;
}
if (!try_module_get(owner)) {
pr_warning("Can't get module reference, dropping event %d\n",
event_type);
kfree(event);
retval = -EINVAL;
goto out;
}
event->type = event_type;
event->object = object;
event->owner = owner;
list_add_tail(&event->node, &serio_event_list);
schedule_work(&serio_event_work);
out:
spin_unlock_irqrestore(&serio_event_lock, flags);
return retval;
}
/* /*
* Remove all events that have been submitted for a given * Remove all events that have been submitted for a given
* object, be it serio port or driver. * object, be it serio port or driver.
...@@ -356,18 +354,6 @@ static struct serio *serio_get_pending_child(struct serio *parent) ...@@ -356,18 +354,6 @@ static struct serio *serio_get_pending_child(struct serio *parent)
return child; return child;
} }
static int serio_thread(void *nothing)
{
do {
serio_handle_event();
wait_event_interruptible(serio_wait,
kthread_should_stop() || !list_empty(&serio_event_list));
} while (!kthread_should_stop());
return 0;
}
/* /*
* Serio port operations * Serio port operations
*/ */
...@@ -1040,21 +1026,18 @@ static int __init serio_init(void) ...@@ -1040,21 +1026,18 @@ static int __init serio_init(void)
return error; return error;
} }
serio_task = kthread_run(serio_thread, NULL, "kseriod");
if (IS_ERR(serio_task)) {
bus_unregister(&serio_bus);
error = PTR_ERR(serio_task);
pr_err("Failed to start kseriod, error: %d\n", error);
return error;
}
return 0; return 0;
} }
static void __exit serio_exit(void) static void __exit serio_exit(void)
{ {
bus_unregister(&serio_bus); bus_unregister(&serio_bus);
kthread_stop(serio_task);
/*
* There should not be any outstanding events but work may
* still be scheduled so simply cancel it.
*/
cancel_work_sync(&serio_event_work);
} }
subsys_initcall(serio_init); subsys_initcall(serio_init);
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include "wacom_wac.h" #include "wacom_wac.h"
#include "wacom.h" #include "wacom.h"
#include <linux/input/mt.h>
static int wacom_penpartner_irq(struct wacom_wac *wacom) static int wacom_penpartner_irq(struct wacom_wac *wacom)
{ {
...@@ -862,19 +863,21 @@ static int wacom_bpt_touch(struct wacom_wac *wacom) ...@@ -862,19 +863,21 @@ static int wacom_bpt_touch(struct wacom_wac *wacom)
struct wacom_features *features = &wacom->features; struct wacom_features *features = &wacom->features;
struct input_dev *input = wacom->input; struct input_dev *input = wacom->input;
unsigned char *data = wacom->data; unsigned char *data = wacom->data;
int sp = 0, sx = 0, sy = 0, count = 0;
int i; int i;
for (i = 0; i < 2; i++) { for (i = 0; i < 2; i++) {
int p = data[9 * i + 2]; int p = data[9 * i + 2];
bool touch = p && !wacom->shared->stylus_in_proximity;
input_mt_slot(input, i); input_mt_slot(input, i);
input_mt_report_slot_state(input, MT_TOOL_FINGER, touch);
/* /*
* Touch events need to be disabled while stylus is * Touch events need to be disabled while stylus is
* in proximity because user's hand is resting on touchpad * in proximity because user's hand is resting on touchpad
* and sending unwanted events. User expects tablet buttons * and sending unwanted events. User expects tablet buttons
* to continue working though. * to continue working though.
*/ */
if (p && !wacom->shared->stylus_in_proximity) { if (touch) {
int x = get_unaligned_be16(&data[9 * i + 3]) & 0x7ff; int x = get_unaligned_be16(&data[9 * i + 3]) & 0x7ff;
int y = get_unaligned_be16(&data[9 * i + 5]) & 0x7ff; int y = get_unaligned_be16(&data[9 * i + 5]) & 0x7ff;
if (features->quirks & WACOM_QUIRK_BBTOUCH_LOWRES) { if (features->quirks & WACOM_QUIRK_BBTOUCH_LOWRES) {
...@@ -884,23 +887,10 @@ static int wacom_bpt_touch(struct wacom_wac *wacom) ...@@ -884,23 +887,10 @@ static int wacom_bpt_touch(struct wacom_wac *wacom)
input_report_abs(input, ABS_MT_PRESSURE, p); input_report_abs(input, ABS_MT_PRESSURE, p);
input_report_abs(input, ABS_MT_POSITION_X, x); input_report_abs(input, ABS_MT_POSITION_X, x);
input_report_abs(input, ABS_MT_POSITION_Y, y); input_report_abs(input, ABS_MT_POSITION_Y, y);
if (wacom->id[i] < 0)
wacom->id[i] = wacom->trk_id++ & MAX_TRACKING_ID;
if (!count++)
sp = p, sx = x, sy = y;
} else {
wacom->id[i] = -1;
} }
input_report_abs(input, ABS_MT_TRACKING_ID, wacom->id[i]);
} }
input_report_key(input, BTN_TOUCH, count > 0); input_mt_report_pointer_emulation(input, true);
input_report_key(input, BTN_TOOL_FINGER, count == 1);
input_report_key(input, BTN_TOOL_DOUBLETAP, count == 2);
input_report_abs(input, ABS_PRESSURE, sp);
input_report_abs(input, ABS_X, sx);
input_report_abs(input, ABS_Y, sy);
input_report_key(input, BTN_LEFT, (data[1] & 0x08) != 0); input_report_key(input, BTN_LEFT, (data[1] & 0x08) != 0);
input_report_key(input, BTN_FORWARD, (data[1] & 0x04) != 0); input_report_key(input, BTN_FORWARD, (data[1] & 0x04) != 0);
...@@ -1272,7 +1262,7 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev, ...@@ -1272,7 +1262,7 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev,
__set_bit(BTN_TOOL_FINGER, input_dev->keybit); __set_bit(BTN_TOOL_FINGER, input_dev->keybit);
__set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit); __set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit);
input_mt_create_slots(input_dev, 2); input_mt_init_slots(input_dev, 2);
input_set_abs_params(input_dev, ABS_MT_POSITION_X, input_set_abs_params(input_dev, ABS_MT_POSITION_X,
0, features->x_max, 0, features->x_max,
features->x_fuzz, 0); features->x_fuzz, 0);
...@@ -1282,8 +1272,6 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev, ...@@ -1282,8 +1272,6 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev,
input_set_abs_params(input_dev, ABS_MT_PRESSURE, input_set_abs_params(input_dev, ABS_MT_PRESSURE,
0, features->pressure_max, 0, features->pressure_max,
features->pressure_fuzz, 0); features->pressure_fuzz, 0);
input_set_abs_params(input_dev, ABS_MT_TRACKING_ID, 0,
MAX_TRACKING_ID, 0, 0);
} else if (features->device_type == BTN_TOOL_PEN) { } else if (features->device_type == BTN_TOOL_PEN) {
__set_bit(BTN_TOOL_RUBBER, input_dev->keybit); __set_bit(BTN_TOOL_RUBBER, input_dev->keybit);
__set_bit(BTN_TOOL_PEN, input_dev->keybit); __set_bit(BTN_TOOL_PEN, input_dev->keybit);
......
...@@ -42,9 +42,6 @@ ...@@ -42,9 +42,6 @@
#define WACOM_QUIRK_MULTI_INPUT 0x0001 #define WACOM_QUIRK_MULTI_INPUT 0x0001
#define WACOM_QUIRK_BBTOUCH_LOWRES 0x0002 #define WACOM_QUIRK_BBTOUCH_LOWRES 0x0002
/* largest reported tracking id */
#define MAX_TRACKING_ID 0xfff
enum { enum {
PENPARTNER = 0, PENPARTNER = 0,
GRAPHIRE, GRAPHIRE,
...@@ -100,7 +97,6 @@ struct wacom_wac { ...@@ -100,7 +97,6 @@ struct wacom_wac {
int id[3]; int id[3];
__u32 serial[2]; __u32 serial[2];
int last_finger; int last_finger;
int trk_id;
struct wacom_features features; struct wacom_features features;
struct wacom_shared *shared; struct wacom_shared *shared;
struct input_dev *input; struct input_dev *input;
......
...@@ -659,17 +659,17 @@ config TOUCHSCREEN_PCAP ...@@ -659,17 +659,17 @@ config TOUCHSCREEN_PCAP
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called pcap_ts. module will be called pcap_ts.
config TOUCHSCREEN_TPS6507X config TOUCHSCREEN_ST1232
tristate "TPS6507x based touchscreens" tristate "Sitronix ST1232 touchscreen controllers"
depends on I2C depends on I2C
help help
Say Y here if you have a TPS6507x based touchscreen Say Y here if you want to support Sitronix ST1232
controller. touchscreen controller.
If unsure, say N. If unsure, say N.
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called tps6507x_ts. module will be called st1232_ts.
config TOUCHSCREEN_STMPE config TOUCHSCREEN_STMPE
tristate "STMicroelectronics STMPE touchscreens" tristate "STMicroelectronics STMPE touchscreens"
...@@ -681,4 +681,16 @@ config TOUCHSCREEN_STMPE ...@@ -681,4 +681,16 @@ config TOUCHSCREEN_STMPE
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called stmpe-ts. module will be called stmpe-ts.
config TOUCHSCREEN_TPS6507X
tristate "TPS6507x based touchscreens"
depends on I2C
help
Say Y here if you have a TPS6507x based touchscreen
controller.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called tps6507x_ts.
endif endif
...@@ -39,6 +39,7 @@ obj-$(CONFIG_TOUCHSCREEN_PCAP) += pcap_ts.o ...@@ -39,6 +39,7 @@ obj-$(CONFIG_TOUCHSCREEN_PCAP) += pcap_ts.o
obj-$(CONFIG_TOUCHSCREEN_PENMOUNT) += penmount.o obj-$(CONFIG_TOUCHSCREEN_PENMOUNT) += penmount.o
obj-$(CONFIG_TOUCHSCREEN_QT602240) += qt602240_ts.o obj-$(CONFIG_TOUCHSCREEN_QT602240) += qt602240_ts.o
obj-$(CONFIG_TOUCHSCREEN_S3C2410) += s3c2410_ts.o obj-$(CONFIG_TOUCHSCREEN_S3C2410) += s3c2410_ts.o
obj-$(CONFIG_TOUCHSCREEN_ST1232) += st1232.o
obj-$(CONFIG_TOUCHSCREEN_STMPE) += stmpe-ts.o obj-$(CONFIG_TOUCHSCREEN_STMPE) += stmpe-ts.o
obj-$(CONFIG_TOUCHSCREEN_TNETV107X) += tnetv107x-ts.o obj-$(CONFIG_TOUCHSCREEN_TNETV107X) += tnetv107x-ts.o
obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213) += touchit213.o obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213) += touchit213.o
......
...@@ -365,7 +365,7 @@ static int bu21013_init_chip(struct bu21013_ts_data *data) ...@@ -365,7 +365,7 @@ static int bu21013_init_chip(struct bu21013_ts_data *data)
} }
retval = i2c_smbus_write_byte_data(i2c, BU21013_TH_OFF_REG, retval = i2c_smbus_write_byte_data(i2c, BU21013_TH_OFF_REG,
BU21013_TH_OFF_4 || BU21013_TH_OFF_3); BU21013_TH_OFF_4 | BU21013_TH_OFF_3);
if (retval < 0) { if (retval < 0) {
dev_err(&i2c->dev, "BU21013_TH_OFF reg write failed\n"); dev_err(&i2c->dev, "BU21013_TH_OFF reg write failed\n");
return retval; return retval;
......
...@@ -969,7 +969,7 @@ static int qt602240_initialize(struct qt602240_data *data) ...@@ -969,7 +969,7 @@ static int qt602240_initialize(struct qt602240_data *data)
return error; return error;
data->object_table = kcalloc(info->object_num, data->object_table = kcalloc(info->object_num,
sizeof(struct qt602240_data), sizeof(struct qt602240_object),
GFP_KERNEL); GFP_KERNEL);
if (!data->object_table) { if (!data->object_table) {
dev_err(&client->dev, "Failed to allocate memory\n"); dev_err(&client->dev, "Failed to allocate memory\n");
...@@ -1324,8 +1324,9 @@ static int __devexit qt602240_remove(struct i2c_client *client) ...@@ -1324,8 +1324,9 @@ static int __devexit qt602240_remove(struct i2c_client *client)
} }
#ifdef CONFIG_PM #ifdef CONFIG_PM
static int qt602240_suspend(struct i2c_client *client, pm_message_t mesg) static int qt602240_suspend(struct device *dev)
{ {
struct i2c_client *client = to_i2c_client(dev);
struct qt602240_data *data = i2c_get_clientdata(client); struct qt602240_data *data = i2c_get_clientdata(client);
struct input_dev *input_dev = data->input_dev; struct input_dev *input_dev = data->input_dev;
...@@ -1339,8 +1340,9 @@ static int qt602240_suspend(struct i2c_client *client, pm_message_t mesg) ...@@ -1339,8 +1340,9 @@ static int qt602240_suspend(struct i2c_client *client, pm_message_t mesg)
return 0; return 0;
} }
static int qt602240_resume(struct i2c_client *client) static int qt602240_resume(struct device *dev)
{ {
struct i2c_client *client = to_i2c_client(dev);
struct qt602240_data *data = i2c_get_clientdata(client); struct qt602240_data *data = i2c_get_clientdata(client);
struct input_dev *input_dev = data->input_dev; struct input_dev *input_dev = data->input_dev;
...@@ -1359,9 +1361,11 @@ static int qt602240_resume(struct i2c_client *client) ...@@ -1359,9 +1361,11 @@ static int qt602240_resume(struct i2c_client *client)
return 0; return 0;
} }
#else
#define qt602240_suspend NULL static const struct dev_pm_ops qt602240_pm_ops = {
#define qt602240_resume NULL .suspend = qt602240_suspend,
.resume = qt602240_resume,
};
#endif #endif
static const struct i2c_device_id qt602240_id[] = { static const struct i2c_device_id qt602240_id[] = {
...@@ -1374,11 +1378,12 @@ static struct i2c_driver qt602240_driver = { ...@@ -1374,11 +1378,12 @@ static struct i2c_driver qt602240_driver = {
.driver = { .driver = {
.name = "qt602240_ts", .name = "qt602240_ts",
.owner = THIS_MODULE, .owner = THIS_MODULE,
#ifdef CONFIG_PM
.pm = &qt602240_pm_ops,
#endif
}, },
.probe = qt602240_probe, .probe = qt602240_probe,
.remove = __devexit_p(qt602240_remove), .remove = __devexit_p(qt602240_remove),
.suspend = qt602240_suspend,
.resume = qt602240_resume,
.id_table = qt602240_id, .id_table = qt602240_id,
}; };
......
/*
* ST1232 Touchscreen Controller Driver
*
* Copyright (C) 2010 Renesas Solutions Corp.
* Tony SIM <chinyeow.sim.xt@renesas.com>
*
* Using code from:
* - android.git.kernel.org: projects/kernel/common.git: synaptics_i2c_rmi.c
* Copyright (C) 2007 Google, Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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/delay.h>
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/types.h>
#define ST1232_TS_NAME "st1232-ts"
#define MIN_X 0x00
#define MIN_Y 0x00
#define MAX_X 0x31f /* (800 - 1) */
#define MAX_Y 0x1df /* (480 - 1) */
#define MAX_AREA 0xff
#define MAX_FINGERS 2
struct st1232_ts_finger {
u16 x;
u16 y;
u8 t;
bool is_valid;
};
struct st1232_ts_data {
struct i2c_client *client;
struct input_dev *input_dev;
struct st1232_ts_finger finger[MAX_FINGERS];
};
static int st1232_ts_read_data(struct st1232_ts_data *ts)
{
struct st1232_ts_finger *finger = ts->finger;
struct i2c_client *client = ts->client;
struct i2c_msg msg[2];
int error;
u8 start_reg;
u8 buf[10];
/* read touchscreen data from ST1232 */
msg[0].addr = client->addr;
msg[0].flags = 0;
msg[0].len = 1;
msg[0].buf = &start_reg;
start_reg = 0x10;
msg[1].addr = ts->client->addr;
msg[1].flags = I2C_M_RD;
msg[1].len = sizeof(buf);
msg[1].buf = buf;
error = i2c_transfer(client->adapter, msg, 2);
if (error < 0)
return error;
/* get "valid" bits */
finger[0].is_valid = buf[2] >> 7;
finger[1].is_valid = buf[5] >> 7;
/* get xy coordinate */
if (finger[0].is_valid) {
finger[0].x = ((buf[2] & 0x0070) << 4) | buf[3];
finger[0].y = ((buf[2] & 0x0007) << 8) | buf[4];
finger[0].t = buf[8];
}
if (finger[1].is_valid) {
finger[1].x = ((buf[5] & 0x0070) << 4) | buf[6];
finger[1].y = ((buf[5] & 0x0007) << 8) | buf[7];
finger[1].t = buf[9];
}
return 0;
}
static irqreturn_t st1232_ts_irq_handler(int irq, void *dev_id)
{
struct st1232_ts_data *ts = dev_id;
struct st1232_ts_finger *finger = ts->finger;
struct input_dev *input_dev = ts->input_dev;
int count = 0;
int i, ret;
ret = st1232_ts_read_data(ts);
if (ret < 0)
goto end;
/* multi touch protocol */
for (i = 0; i < MAX_FINGERS; i++) {
if (!finger[i].is_valid)
continue;
input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR, finger[i].t);
input_report_abs(input_dev, ABS_MT_POSITION_X, finger[i].x);
input_report_abs(input_dev, ABS_MT_POSITION_Y, finger[i].y);
input_mt_sync(input_dev);
count++;
}
/* SYN_MT_REPORT only if no contact */
if (!count)
input_mt_sync(input_dev);
/* SYN_REPORT */
input_sync(input_dev);
end:
return IRQ_HANDLED;
}
static int __devinit st1232_ts_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct st1232_ts_data *ts;
struct input_dev *input_dev;
int error;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
dev_err(&client->dev, "need I2C_FUNC_I2C\n");
return -EIO;
}
if (!client->irq) {
dev_err(&client->dev, "no IRQ?\n");
return -EINVAL;
}
ts = kzalloc(sizeof(struct st1232_ts_data), GFP_KERNEL);
input_dev = input_allocate_device();
if (!ts || !input_dev) {
error = -ENOMEM;
goto err_free_mem;
}
ts->client = client;
ts->input_dev = input_dev;
input_dev->name = "st1232-touchscreen";
input_dev->id.bustype = BUS_I2C;
input_dev->dev.parent = &client->dev;
__set_bit(EV_SYN, input_dev->evbit);
__set_bit(EV_KEY, input_dev->evbit);
__set_bit(EV_ABS, input_dev->evbit);
input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, MAX_AREA, 0, 0);
input_set_abs_params(input_dev, ABS_MT_POSITION_X, MIN_X, MAX_X, 0, 0);
input_set_abs_params(input_dev, ABS_MT_POSITION_Y, MIN_Y, MAX_Y, 0, 0);
error = request_threaded_irq(client->irq, NULL, st1232_ts_irq_handler,
IRQF_ONESHOT, client->name, ts);
if (error) {
dev_err(&client->dev, "Failed to register interrupt\n");
goto err_free_mem;
}
error = input_register_device(ts->input_dev);
if (error) {
dev_err(&client->dev, "Unable to register %s input device\n",
input_dev->name);
goto err_free_irq;
}
i2c_set_clientdata(client, ts);
device_init_wakeup(&client->dev, 1);
return 0;
err_free_irq:
free_irq(client->irq, ts);
err_free_mem:
input_free_device(input_dev);
kfree(ts);
return error;
}
static int __devexit st1232_ts_remove(struct i2c_client *client)
{
struct st1232_ts_data *ts = i2c_get_clientdata(client);
device_init_wakeup(&client->dev, 0);
free_irq(client->irq, ts);
input_unregister_device(ts->input_dev);
kfree(ts);
return 0;
}
#ifdef CONFIG_PM
static int st1232_ts_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
if (device_may_wakeup(&client->dev))
enable_irq_wake(client->irq);
else
disable_irq(client->irq);
return 0;
}
static int st1232_ts_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
if (device_may_wakeup(&client->dev))
disable_irq_wake(client->irq);
else
enable_irq(client->irq);
return 0;
}
static const struct dev_pm_ops st1232_ts_pm_ops = {
.suspend = st1232_ts_suspend,
.resume = st1232_ts_resume,
};
#endif
static const struct i2c_device_id st1232_ts_id[] = {
{ ST1232_TS_NAME, 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, st1232_ts_id);
static struct i2c_driver st1232_ts_driver = {
.probe = st1232_ts_probe,
.remove = __devexit_p(st1232_ts_remove),
.id_table = st1232_ts_id,
.driver = {
.name = ST1232_TS_NAME,
.owner = THIS_MODULE,
#ifdef CONFIG_PM
.pm = &st1232_ts_pm_ops,
#endif
},
};
static int __init st1232_ts_init(void)
{
return i2c_add_driver(&st1232_ts_driver);
}
module_init(st1232_ts_init);
static void __exit st1232_ts_exit(void)
{
i2c_del_driver(&st1232_ts_driver);
}
module_exit(st1232_ts_exit);
MODULE_AUTHOR("Tony SIM <chinyeow.sim.xt@renesas.com>");
MODULE_DESCRIPTION("SITRONIX ST1232 Touchscreen Controller Driver");
MODULE_LICENSE("GPL");
...@@ -15,10 +15,11 @@ ...@@ -15,10 +15,11 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/input.h> #include <linux/input/mt.h>
#include <linux/serio.h> #include <linux/serio.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/ctype.h> #include <linux/ctype.h>
#include <linux/delay.h>
#define DRIVER_DESC "Wacom W8001 serial touchscreen driver" #define DRIVER_DESC "Wacom W8001 serial touchscreen driver"
...@@ -37,6 +38,7 @@ MODULE_LICENSE("GPL"); ...@@ -37,6 +38,7 @@ MODULE_LICENSE("GPL");
#define W8001_QUERY_PACKET 0x20 #define W8001_QUERY_PACKET 0x20
#define W8001_CMD_STOP '0'
#define W8001_CMD_START '1' #define W8001_CMD_START '1'
#define W8001_CMD_QUERY '*' #define W8001_CMD_QUERY '*'
#define W8001_CMD_TOUCHQUERY '%' #define W8001_CMD_TOUCHQUERY '%'
...@@ -48,8 +50,6 @@ MODULE_LICENSE("GPL"); ...@@ -48,8 +50,6 @@ MODULE_LICENSE("GPL");
#define W8001_PKTLEN_TPCCTL 11 /* control packet */ #define W8001_PKTLEN_TPCCTL 11 /* control packet */
#define W8001_PKTLEN_TOUCH2FG 13 #define W8001_PKTLEN_TOUCH2FG 13
#define MAX_TRACKING_ID 0xFF /* arbitrarily chosen */
struct w8001_coord { struct w8001_coord {
u8 rdy; u8 rdy;
u8 tsw; u8 tsw;
...@@ -87,7 +87,6 @@ struct w8001 { ...@@ -87,7 +87,6 @@ struct w8001 {
char phys[32]; char phys[32];
int type; int type;
unsigned int pktlen; unsigned int pktlen;
int trkid[2];
}; };
static void parse_data(u8 *data, struct w8001_coord *coord) static void parse_data(u8 *data, struct w8001_coord *coord)
...@@ -116,28 +115,23 @@ static void parse_data(u8 *data, struct w8001_coord *coord) ...@@ -116,28 +115,23 @@ static void parse_data(u8 *data, struct w8001_coord *coord)
static void parse_touch(struct w8001 *w8001) static void parse_touch(struct w8001 *w8001)
{ {
static int trkid;
struct input_dev *dev = w8001->dev; struct input_dev *dev = w8001->dev;
unsigned char *data = w8001->data; unsigned char *data = w8001->data;
int i; int i;
for (i = 0; i < 2; i++) { for (i = 0; i < 2; i++) {
input_mt_slot(dev, i); bool touch = data[0] & (1 << i);
if (data[0] & (1 << i)) { input_mt_slot(dev, i);
input_mt_report_slot_state(dev, MT_TOOL_FINGER, touch);
if (touch) {
int x = (data[6 * i + 1] << 7) | (data[6 * i + 2]); int x = (data[6 * i + 1] << 7) | (data[6 * i + 2]);
int y = (data[6 * i + 3] << 7) | (data[6 * i + 4]); int y = (data[6 * i + 3] << 7) | (data[6 * i + 4]);
/* data[5,6] and [11,12] is finger capacity */ /* data[5,6] and [11,12] is finger capacity */
input_report_abs(dev, ABS_MT_POSITION_X, x); input_report_abs(dev, ABS_MT_POSITION_X, x);
input_report_abs(dev, ABS_MT_POSITION_Y, y); input_report_abs(dev, ABS_MT_POSITION_Y, y);
input_report_abs(dev, ABS_MT_TOOL_TYPE, MT_TOOL_FINGER);
if (w8001->trkid[i] < 0)
w8001->trkid[i] = trkid++ & MAX_TRACKING_ID;
} else {
w8001->trkid[i] = -1;
} }
input_report_abs(dev, ABS_MT_TRACKING_ID, w8001->trkid[i]);
} }
input_sync(dev); input_sync(dev);
...@@ -287,24 +281,46 @@ static int w8001_setup(struct w8001 *w8001) ...@@ -287,24 +281,46 @@ static int w8001_setup(struct w8001 *w8001)
struct w8001_coord coord; struct w8001_coord coord;
int error; int error;
error = w8001_command(w8001, W8001_CMD_QUERY, true); error = w8001_command(w8001, W8001_CMD_STOP, false);
if (error) if (error)
return error; return error;
parse_data(w8001->response, &coord); msleep(250); /* wait 250ms before querying the device */
input_set_abs_params(dev, ABS_X, 0, coord.x, 0, 0); /* penabled? */
input_set_abs_params(dev, ABS_Y, 0, coord.y, 0, 0); error = w8001_command(w8001, W8001_CMD_QUERY, true);
input_set_abs_params(dev, ABS_PRESSURE, 0, coord.pen_pressure, 0, 0); if (!error) {
input_set_abs_params(dev, ABS_TILT_X, 0, coord.tilt_x, 0, 0); __set_bit(BTN_TOOL_PEN, dev->keybit);
input_set_abs_params(dev, ABS_TILT_Y, 0, coord.tilt_y, 0, 0); __set_bit(BTN_TOOL_RUBBER, dev->keybit);
__set_bit(BTN_STYLUS, dev->keybit);
__set_bit(BTN_STYLUS2, dev->keybit);
parse_data(w8001->response, &coord);
input_set_abs_params(dev, ABS_X, 0, coord.x, 0, 0);
input_set_abs_params(dev, ABS_Y, 0, coord.y, 0, 0);
input_set_abs_params(dev, ABS_PRESSURE, 0, coord.pen_pressure, 0, 0);
if (coord.tilt_x && coord.tilt_y) {
input_set_abs_params(dev, ABS_TILT_X, 0, coord.tilt_x, 0, 0);
input_set_abs_params(dev, ABS_TILT_Y, 0, coord.tilt_y, 0, 0);
}
}
/* Touch enabled? */
error = w8001_command(w8001, W8001_CMD_TOUCHQUERY, true); error = w8001_command(w8001, W8001_CMD_TOUCHQUERY, true);
if (!error) {
/*
* Some non-touch devices may reply to the touch query. But their
* second byte is empty, which indicates touch is not supported.
*/
if (!error && w8001->response[1]) {
struct w8001_touch_query touch; struct w8001_touch_query touch;
parse_touchquery(w8001->response, &touch); parse_touchquery(w8001->response, &touch);
input_set_abs_params(dev, ABS_X, 0, touch.x, 0, 0);
input_set_abs_params(dev, ABS_Y, 0, touch.y, 0, 0);
__set_bit(BTN_TOOL_FINGER, dev->keybit);
switch (touch.sensor_id) { switch (touch.sensor_id) {
case 0: case 0:
case 2: case 2:
...@@ -318,15 +334,13 @@ static int w8001_setup(struct w8001 *w8001) ...@@ -318,15 +334,13 @@ static int w8001_setup(struct w8001 *w8001)
case 5: case 5:
w8001->pktlen = W8001_PKTLEN_TOUCH2FG; w8001->pktlen = W8001_PKTLEN_TOUCH2FG;
input_mt_create_slots(dev, 2); input_mt_init_slots(dev, 2);
input_set_abs_params(dev, ABS_MT_TRACKING_ID,
0, MAX_TRACKING_ID, 0, 0);
input_set_abs_params(dev, ABS_MT_POSITION_X, input_set_abs_params(dev, ABS_MT_POSITION_X,
0, touch.x, 0, 0); 0, touch.x, 0, 0);
input_set_abs_params(dev, ABS_MT_POSITION_Y, input_set_abs_params(dev, ABS_MT_POSITION_Y,
0, touch.y, 0, 0); 0, touch.y, 0, 0);
input_set_abs_params(dev, ABS_MT_TOOL_TYPE, input_set_abs_params(dev, ABS_MT_TOOL_TYPE,
0, 0, 0, 0); 0, MT_TOOL_MAX, 0, 0);
break; break;
} }
} }
...@@ -372,7 +386,6 @@ static int w8001_connect(struct serio *serio, struct serio_driver *drv) ...@@ -372,7 +386,6 @@ static int w8001_connect(struct serio *serio, struct serio_driver *drv)
w8001->serio = serio; w8001->serio = serio;
w8001->id = serio->id.id; w8001->id = serio->id.id;
w8001->dev = input_dev; w8001->dev = input_dev;
w8001->trkid[0] = w8001->trkid[1] = -1;
init_completion(&w8001->cmd_done); init_completion(&w8001->cmd_done);
snprintf(w8001->phys, sizeof(w8001->phys), "%s/input0", serio->phys); snprintf(w8001->phys, sizeof(w8001->phys), "%s/input0", serio->phys);
...@@ -385,11 +398,7 @@ static int w8001_connect(struct serio *serio, struct serio_driver *drv) ...@@ -385,11 +398,7 @@ static int w8001_connect(struct serio *serio, struct serio_driver *drv)
input_dev->dev.parent = &serio->dev; input_dev->dev.parent = &serio->dev;
input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); __set_bit(BTN_TOUCH, input_dev->keybit);
input_dev->keybit[BIT_WORD(BTN_TOOL_PEN)] |= BIT_MASK(BTN_TOOL_PEN);
input_dev->keybit[BIT_WORD(BTN_TOOL_RUBBER)] |= BIT_MASK(BTN_TOOL_RUBBER);
input_dev->keybit[BIT_WORD(BTN_STYLUS)] |= BIT_MASK(BTN_STYLUS);
input_dev->keybit[BIT_WORD(BTN_STYLUS2)] |= BIT_MASK(BTN_STYLUS2);
serio_set_drvdata(serio, w8001); serio_set_drvdata(serio, w8001);
err = serio_open(serio, drv); err = serio_open(serio, drv);
......
...@@ -17,6 +17,8 @@ ...@@ -17,6 +17,8 @@
* Switch to grant tables together with xen-fbfront.c. * Switch to grant tables together with xen-fbfront.c.
*/ */
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/module.h> #include <linux/module.h>
...@@ -84,9 +86,8 @@ static irqreturn_t input_handler(int rq, void *dev_id) ...@@ -84,9 +86,8 @@ static irqreturn_t input_handler(int rq, void *dev_id)
input_report_key(dev, event->key.keycode, input_report_key(dev, event->key.keycode,
event->key.pressed); event->key.pressed);
else else
printk(KERN_WARNING pr_warning("unhandled keycode 0x%x\n",
"xenkbd: unhandled keycode 0x%x\n", event->key.keycode);
event->key.keycode);
break; break;
case XENKBD_TYPE_POS: case XENKBD_TYPE_POS:
input_report_abs(dev, ABS_X, event->pos.abs_x); input_report_abs(dev, ABS_X, event->pos.abs_x);
...@@ -292,8 +293,7 @@ static void xenkbd_backend_changed(struct xenbus_device *dev, ...@@ -292,8 +293,7 @@ static void xenkbd_backend_changed(struct xenbus_device *dev,
ret = xenbus_printf(XBT_NIL, info->xbdev->nodename, ret = xenbus_printf(XBT_NIL, info->xbdev->nodename,
"request-abs-pointer", "1"); "request-abs-pointer", "1");
if (ret) if (ret)
printk(KERN_WARNING pr_warning("can't request abs-pointer\n");
"xenkbd: can't request abs-pointer");
} }
xenbus_switch_state(dev, XenbusStateConnected); xenbus_switch_state(dev, XenbusStateConnected);
break; break;
......
...@@ -23,6 +23,8 @@ static int mouse_button3_keycode = KEY_RIGHTALT; /* right option key */ ...@@ -23,6 +23,8 @@ static int mouse_button3_keycode = KEY_RIGHTALT; /* right option key */
static struct input_dev *mac_hid_emumouse_dev; static struct input_dev *mac_hid_emumouse_dev;
static DEFINE_MUTEX(mac_hid_emumouse_mutex);
static int mac_hid_create_emumouse(void) static int mac_hid_create_emumouse(void)
{ {
static struct lock_class_key mac_hid_emumouse_dev_event_class; static struct lock_class_key mac_hid_emumouse_dev_event_class;
...@@ -187,6 +189,10 @@ static int mac_hid_toggle_emumouse(ctl_table *table, int write, ...@@ -187,6 +189,10 @@ static int mac_hid_toggle_emumouse(ctl_table *table, int write,
int old_val = *valp; int old_val = *valp;
int rc; int rc;
rc = mutex_lock_killable(&mac_hid_emumouse_mutex);
if (rc)
return rc;
rc = proc_dointvec(table, write, buffer, lenp, ppos); rc = proc_dointvec(table, write, buffer, lenp, ppos);
if (rc == 0 && write && *valp != old_val) { if (rc == 0 && write && *valp != old_val) {
...@@ -202,6 +208,8 @@ static int mac_hid_toggle_emumouse(ctl_table *table, int write, ...@@ -202,6 +208,8 @@ static int mac_hid_toggle_emumouse(ctl_table *table, int write,
if (rc) if (rc)
*valp = old_val; *valp = old_val;
mutex_unlock(&mac_hid_emumouse_mutex);
return rc; return rc;
} }
......
...@@ -112,6 +112,7 @@ struct input_keymap_entry { ...@@ -112,6 +112,7 @@ struct input_keymap_entry {
#define EVIOCGNAME(len) _IOC(_IOC_READ, 'E', 0x06, len) /* get device name */ #define EVIOCGNAME(len) _IOC(_IOC_READ, 'E', 0x06, len) /* get device name */
#define EVIOCGPHYS(len) _IOC(_IOC_READ, 'E', 0x07, len) /* get physical location */ #define EVIOCGPHYS(len) _IOC(_IOC_READ, 'E', 0x07, len) /* get physical location */
#define EVIOCGUNIQ(len) _IOC(_IOC_READ, 'E', 0x08, len) /* get unique identifier */ #define EVIOCGUNIQ(len) _IOC(_IOC_READ, 'E', 0x08, len) /* get unique identifier */
#define EVIOCGPROP(len) _IOC(_IOC_READ, 'E', 0x09, len) /* get device properties */
#define EVIOCGKEY(len) _IOC(_IOC_READ, 'E', 0x18, len) /* get global key state */ #define EVIOCGKEY(len) _IOC(_IOC_READ, 'E', 0x18, len) /* get global key state */
#define EVIOCGLED(len) _IOC(_IOC_READ, 'E', 0x19, len) /* get all LEDs */ #define EVIOCGLED(len) _IOC(_IOC_READ, 'E', 0x19, len) /* get all LEDs */
...@@ -128,6 +129,18 @@ struct input_keymap_entry { ...@@ -128,6 +129,18 @@ struct input_keymap_entry {
#define EVIOCGRAB _IOW('E', 0x90, int) /* Grab/Release device */ #define EVIOCGRAB _IOW('E', 0x90, int) /* Grab/Release device */
/*
* Device properties and quirks
*/
#define INPUT_PROP_POINTER 0x00 /* needs a pointer */
#define INPUT_PROP_DIRECT 0x01 /* direct input devices */
#define INPUT_PROP_BUTTONPAD 0x02 /* has button(s) under pad */
#define INPUT_PROP_SEMI_MT 0x03 /* touch rectangle only */
#define INPUT_PROP_MAX 0x1f
#define INPUT_PROP_CNT (INPUT_PROP_MAX + 1)
/* /*
* Event types * Event types
*/ */
...@@ -758,11 +771,12 @@ struct input_keymap_entry { ...@@ -758,11 +771,12 @@ struct input_keymap_entry {
#define ABS_MT_BLOB_ID 0x38 /* Group a set of packets as a blob */ #define ABS_MT_BLOB_ID 0x38 /* Group a set of packets as a blob */
#define ABS_MT_TRACKING_ID 0x39 /* Unique ID of initiated contact */ #define ABS_MT_TRACKING_ID 0x39 /* Unique ID of initiated contact */
#define ABS_MT_PRESSURE 0x3a /* Pressure on contact area */ #define ABS_MT_PRESSURE 0x3a /* Pressure on contact area */
#define ABS_MT_DISTANCE 0x3b /* Contact hover distance */
#ifdef __KERNEL__ #ifdef __KERNEL__
/* Implementation details, userspace should not care about these */ /* Implementation details, userspace should not care about these */
#define ABS_MT_FIRST ABS_MT_TOUCH_MAJOR #define ABS_MT_FIRST ABS_MT_TOUCH_MAJOR
#define ABS_MT_LAST ABS_MT_PRESSURE #define ABS_MT_LAST ABS_MT_DISTANCE
#endif #endif
#define ABS_MAX 0x3f #define ABS_MAX 0x3f
...@@ -873,6 +887,7 @@ struct input_keymap_entry { ...@@ -873,6 +887,7 @@ struct input_keymap_entry {
*/ */
#define MT_TOOL_FINGER 0 #define MT_TOOL_FINGER 0
#define MT_TOOL_PEN 1 #define MT_TOOL_PEN 1
#define MT_TOOL_MAX 1
/* /*
* Values describing the status of a force-feedback effect * Values describing the status of a force-feedback effect
...@@ -1107,20 +1122,13 @@ struct ff_effect { ...@@ -1107,20 +1122,13 @@ struct ff_effect {
#include <linux/timer.h> #include <linux/timer.h>
#include <linux/mod_devicetable.h> #include <linux/mod_devicetable.h>
/**
* struct input_mt_slot - represents the state of an input MT slot
* @abs: holds current values of ABS_MT axes for this slot
*/
struct input_mt_slot {
int abs[ABS_MT_LAST - ABS_MT_FIRST + 1];
};
/** /**
* struct input_dev - represents an input device * struct input_dev - represents an input device
* @name: name of the device * @name: name of the device
* @phys: physical path to the device in the system hierarchy * @phys: physical path to the device in the system hierarchy
* @uniq: unique identification code for the device (if device has it) * @uniq: unique identification code for the device (if device has it)
* @id: id of the device (struct input_id) * @id: id of the device (struct input_id)
* @propbit: bitmap of device properties and quirks
* @evbit: bitmap of types of events supported by the device (EV_KEY, * @evbit: bitmap of types of events supported by the device (EV_KEY,
* EV_REL, etc.) * EV_REL, etc.)
* @keybit: bitmap of keys/buttons this device has * @keybit: bitmap of keys/buttons this device has
...@@ -1155,6 +1163,7 @@ struct input_mt_slot { ...@@ -1155,6 +1163,7 @@ struct input_mt_slot {
* of tracked contacts * of tracked contacts
* @mtsize: number of MT slots the device uses * @mtsize: number of MT slots the device uses
* @slot: MT slot currently being transmitted * @slot: MT slot currently being transmitted
* @trkid: stores MT tracking ID for the current contact
* @absinfo: array of &struct input_absinfo elements holding information * @absinfo: array of &struct input_absinfo elements holding information
* about absolute axes (current value, min, max, flat, fuzz, * about absolute axes (current value, min, max, flat, fuzz,
* resolution) * resolution)
...@@ -1203,6 +1212,8 @@ struct input_dev { ...@@ -1203,6 +1212,8 @@ struct input_dev {
const char *uniq; const char *uniq;
struct input_id id; struct input_id id;
unsigned long propbit[BITS_TO_LONGS(INPUT_PROP_CNT)];
unsigned long evbit[BITS_TO_LONGS(EV_CNT)]; unsigned long evbit[BITS_TO_LONGS(EV_CNT)];
unsigned long keybit[BITS_TO_LONGS(KEY_CNT)]; unsigned long keybit[BITS_TO_LONGS(KEY_CNT)];
unsigned long relbit[BITS_TO_LONGS(REL_CNT)]; unsigned long relbit[BITS_TO_LONGS(REL_CNT)];
...@@ -1239,6 +1250,7 @@ struct input_dev { ...@@ -1239,6 +1250,7 @@ struct input_dev {
struct input_mt_slot *mt; struct input_mt_slot *mt;
int mtsize; int mtsize;
int slot; int slot;
int trkid;
struct input_absinfo *absinfo; struct input_absinfo *absinfo;
...@@ -1488,11 +1500,6 @@ static inline void input_mt_sync(struct input_dev *dev) ...@@ -1488,11 +1500,6 @@ static inline void input_mt_sync(struct input_dev *dev)
input_event(dev, EV_SYN, SYN_MT_REPORT, 0); input_event(dev, EV_SYN, SYN_MT_REPORT, 0);
} }
static inline void input_mt_slot(struct input_dev *dev, int slot)
{
input_event(dev, EV_ABS, ABS_MT_SLOT, slot);
}
void input_set_capability(struct input_dev *dev, unsigned int type, unsigned int code); void input_set_capability(struct input_dev *dev, unsigned int type, unsigned int code);
/** /**
...@@ -1605,8 +1612,5 @@ int input_ff_erase(struct input_dev *dev, int effect_id, struct file *file); ...@@ -1605,8 +1612,5 @@ int input_ff_erase(struct input_dev *dev, int effect_id, struct file *file);
int input_ff_create_memless(struct input_dev *dev, void *data, int input_ff_create_memless(struct input_dev *dev, void *data,
int (*play_effect)(struct input_dev *, void *, struct ff_effect *)); int (*play_effect)(struct input_dev *, void *, struct ff_effect *));
int input_mt_create_slots(struct input_dev *dev, unsigned int num_slots);
void input_mt_destroy_slots(struct input_dev *dev);
#endif #endif
#endif #endif
/*
* VTI CMA3000_Dxx Accelerometer driver
*
* Copyright (C) 2010 Texas Instruments
* Author: Hemanth V <hemanthv@ti.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License 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.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _LINUX_CMA3000_H
#define _LINUX_CMA3000_H
#define CMAMODE_DEFAULT 0
#define CMAMODE_MEAS100 1
#define CMAMODE_MEAS400 2
#define CMAMODE_MEAS40 3
#define CMAMODE_MOTDET 4
#define CMAMODE_FF100 5
#define CMAMODE_FF400 6
#define CMAMODE_POFF 7
#define CMARANGE_2G 2000
#define CMARANGE_8G 8000
/**
* struct cma3000_i2c_platform_data - CMA3000 Platform data
* @fuzz_x: Noise on X Axis
* @fuzz_y: Noise on Y Axis
* @fuzz_z: Noise on Z Axis
* @g_range: G range in milli g i.e 2000 or 8000
* @mode: Operating mode
* @mdthr: Motion detect threshold value
* @mdfftmr: Motion detect and free fall time value
* @ffthr: Free fall threshold value
*/
struct cma3000_platform_data {
int fuzz_x;
int fuzz_y;
int fuzz_z;
int g_range;
uint8_t mode;
uint8_t mdthr;
uint8_t mdfftmr;
uint8_t ffthr;
unsigned long irqflags;
};
#endif
#ifndef _INPUT_MT_H
#define _INPUT_MT_H
/*
* Input Multitouch Library
*
* Copyright (c) 2010 Henrik Rydberg
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*/
#include <linux/input.h>
#define TRKID_MAX 0xffff
/**
* struct input_mt_slot - represents the state of an input MT slot
* @abs: holds current values of ABS_MT axes for this slot
*/
struct input_mt_slot {
int abs[ABS_MT_LAST - ABS_MT_FIRST + 1];
};
static inline void input_mt_set_value(struct input_mt_slot *slot,
unsigned code, int value)
{
slot->abs[code - ABS_MT_FIRST] = value;
}
static inline int input_mt_get_value(const struct input_mt_slot *slot,
unsigned code)
{
return slot->abs[code - ABS_MT_FIRST];
}
int input_mt_init_slots(struct input_dev *dev, unsigned int num_slots);
void input_mt_destroy_slots(struct input_dev *dev);
static inline int input_mt_new_trkid(struct input_dev *dev)
{
return dev->trkid++ & TRKID_MAX;
}
static inline void input_mt_slot(struct input_dev *dev, int slot)
{
input_event(dev, EV_ABS, ABS_MT_SLOT, slot);
}
void input_mt_report_slot_state(struct input_dev *dev,
unsigned int tool_type, bool active);
void input_mt_report_finger_count(struct input_dev *dev, int count);
void input_mt_report_pointer_emulation(struct input_dev *dev, bool use_count);
#endif
...@@ -104,6 +104,7 @@ struct uinput_ff_erase { ...@@ -104,6 +104,7 @@ struct uinput_ff_erase {
#define UI_SET_FFBIT _IOW(UINPUT_IOCTL_BASE, 107, int) #define UI_SET_FFBIT _IOW(UINPUT_IOCTL_BASE, 107, int)
#define UI_SET_PHYS _IOW(UINPUT_IOCTL_BASE, 108, char*) #define UI_SET_PHYS _IOW(UINPUT_IOCTL_BASE, 108, char*)
#define UI_SET_SWBIT _IOW(UINPUT_IOCTL_BASE, 109, int) #define UI_SET_SWBIT _IOW(UINPUT_IOCTL_BASE, 109, int)
#define UI_SET_PROPBIT _IOW(UINPUT_IOCTL_BASE, 110, int)
#define UI_BEGIN_FF_UPLOAD _IOWR(UINPUT_IOCTL_BASE, 200, struct uinput_ff_upload) #define UI_BEGIN_FF_UPLOAD _IOWR(UINPUT_IOCTL_BASE, 200, struct uinput_ff_upload)
#define UI_END_FF_UPLOAD _IOW(UINPUT_IOCTL_BASE, 201, struct uinput_ff_upload) #define UI_END_FF_UPLOAD _IOW(UINPUT_IOCTL_BASE, 201, struct uinput_ff_upload)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment