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
!Edrivers/input/input.c
!Edrivers/input/ff-core.c
!Edrivers/input/ff-memless.c
</sect1>
<sect1><title>Multitouch Library</title>
!Iinclude/linux/input/mt.h
!Edrivers/input/input-mt.c
</sect1>
<sect1><title>Polled input devices</title>
!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
-------------------------
Copyright (C) 2009 Henrik Rydberg <rydberg@euromail.se>
Copyright (C) 2009-2010 Henrik Rydberg <rydberg@euromail.se>
Introduction
......@@ -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
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
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
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
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
contact or a pen or something else. Devices with more granular information
may specify general shapes as blobs, i.e., as a sequence of rectangular
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
report contact tracking from hardware [5].
finger or a pen or something else. Finally, the ABS_MT_TRACKING_ID event
may be used to track identified contacts over time [5].
In the type B protocol, ABS_MT_TOOL_TYPE and ABS_MT_TRACKING_ID are
implicitly handled by input core; drivers should instead call
input_mt_report_slot_state().
Event Semantics
......@@ -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
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
The orientation of the ellipse. The value should describe a signed quarter
......@@ -240,21 +251,24 @@ ABS_MT_TOOL_TYPE
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
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
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
devices do not have blob capability, so drivers can safely omit this event.
ABS_MT_TRACKING_ID
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
TRACKING_ID should be large enough to ensure unique identification of a
contact maintained over an extended period of time.
[5]. The value range of the TRACKING_ID should be large enough to ensure
unique identification of a contact maintained over an extended period of
time. For type B devices, this event is handled by input core; drivers
should instead use input_mt_report_slot_state().
Event Computation
......@@ -301,18 +315,19 @@ and with ORIENTATION, one can detect twisting of fingers.
Notes
-----
In order to stay compatible with existing applications, the data
reported in a finger packet must not be recognized as single-touch
events. In addition, all finger data must bypass input filtering,
since subsequent events of the same type refer to different fingers.
In order to stay compatible with existing applications, the data reported
in a finger packet must not be recognized as single-touch events.
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,
where examples can be found.
For example usage of the type A protocol, see the bcm5974 driver. For
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
difference between the contact position and the approaching tool position
could be used to derive tilt.
[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.
[5] See the section on finger tracking.
......@@ -3020,8 +3020,10 @@ F: drivers/input/
INPUT MULTITOUCH (MT) PROTOCOL
M: Henrik Rydberg <rydberg@euromail.se>
L: linux-input@vger.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/rydberg/input-mt.git
S: Maintained
F: Documentation/input/multi-touch-protocol.txt
F: drivers/input/input-mt.c
K: \b(ABS|SYN)_MT_
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
tristate "eGalax multi-touch panel"
depends on USB_HID
---help---
Support for the eGalax dual-touch panel.
Support for the eGalax dual-touch panels, including the
Joojoo and Wetab tablets.
config HID_ELECOM
tristate "ELECOM BM084 bluetooth mouse"
......
......@@ -19,6 +19,7 @@
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/usb.h>
#include <linux/input/mt.h>
MODULE_AUTHOR("Stephane Chatty <chatty@enac.fr>");
MODULE_DESCRIPTION("3M PCT multitouch panels");
......@@ -27,8 +28,6 @@ MODULE_LICENSE("GPL");
#include "hid-ids.h"
#define MAX_SLOTS 60
#define MAX_TRKID USHRT_MAX
#define MAX_EVENTS 360
/* estimated signal-to-noise ratios */
#define SN_MOVE 2048
......@@ -36,14 +35,11 @@ MODULE_LICENSE("GPL");
struct mmm_finger {
__s32 x, y, w, h;
__u16 id;
bool prev_touch;
bool touch, valid;
};
struct mmm_data {
struct mmm_finger f[MAX_SLOTS];
__u16 id;
__u8 curid;
__u8 nexp, nreal;
bool touch, valid;
......@@ -117,14 +113,7 @@ static int mmm_input_mapping(struct hid_device *hdev, struct hid_input *hi,
0, 1, 0, 0);
return 1;
case HID_DG_CONTACTID:
field->logical_maximum = MAX_TRKID;
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);
input_mt_init_slots(hi->input, MAX_SLOTS);
return 1;
}
/* let hid-input decide for the others */
......@@ -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)
{
struct mmm_finger *oldest = 0;
int i;
for (i = 0; i < MAX_SLOTS; ++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)
continue;
}
input_mt_slot(input, i);
input_mt_report_slot_state(input, MT_TOOL_FINGER, f->touch);
if (f->touch) {
/* this finger is on the screen */
int wide = (f->w > f->h);
......@@ -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 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_Y, f->y);
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_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;
}
/* touchscreen emulation */
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_mt_report_pointer_emulation(input, true);
input_sync(input);
}
......
......@@ -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_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_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_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) },
......
......@@ -2,6 +2,8 @@
* HID driver for eGalax dual-touch panels
*
* 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 @@
#include <linux/hid.h>
#include <linux/module.h>
#include <linux/usb.h>
#include <linux/input/mt.h>
#include <linux/slab.h>
#include "usbhid/usbhid.h"
......@@ -25,38 +28,53 @@ MODULE_LICENSE("GPL");
#include "hid-ids.h"
#define MAX_SLOTS 2
/* estimated signal-to-noise ratios */
#define SN_MOVE 4096
#define SN_PRESSURE 32
struct egalax_data {
__u16 x, y, z;
__u8 id;
bool first; /* is this the first finger in the frame? */
bool valid; /* valid finger data, or just placeholder? */
bool activity; /* at least one active finger previously? */
__u16 lastx, lasty, lastz; /* latest valid (x, y, z) in the frame */
int valid;
int slot;
int touch;
int x, y, z;
};
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,
struct hid_field *field, struct hid_usage *usage,
unsigned long **bit, int *max)
{
struct input_dev *input = hi->input;
switch (usage->hid & HID_USAGE_PAGE) {
case HID_UP_GENDESK:
switch (usage->hid) {
case HID_GD_X:
field->logical_maximum = 32760;
hid_map_usage(hi, usage, bit, max,
EV_ABS, ABS_MT_POSITION_X);
set_abs(input, ABS_MT_POSITION_X, field, SN_MOVE);
/* touchscreen emulation */
input_set_abs_params(hi->input, ABS_X,
field->logical_minimum,
field->logical_maximum, 0, 0);
set_abs(input, ABS_X, field, SN_MOVE);
return 1;
case HID_GD_Y:
field->logical_maximum = 32760;
hid_map_usage(hi, usage, bit, max,
EV_ABS, ABS_MT_POSITION_Y);
set_abs(input, ABS_MT_POSITION_Y, field, SN_MOVE);
/* touchscreen emulation */
input_set_abs_params(hi->input, ABS_Y,
field->logical_minimum,
field->logical_maximum, 0, 0);
set_abs(input, ABS_Y, field, SN_MOVE);
return 1;
}
return 0;
......@@ -66,6 +84,7 @@ static int egalax_input_mapping(struct hid_device *hdev, struct hid_input *hi,
case HID_DG_TIPSWITCH:
/* touchscreen emulation */
hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH);
input_set_capability(input, EV_KEY, BTN_TOUCH);
return 1;
case HID_DG_INRANGE:
case HID_DG_CONFIDENCE:
......@@ -73,16 +92,15 @@ static int egalax_input_mapping(struct hid_device *hdev, struct hid_input *hi,
case HID_DG_CONTACTMAX:
return -1;
case HID_DG_CONTACTID:
hid_map_usage(hi, usage, bit, max,
EV_ABS, ABS_MT_TRACKING_ID);
input_mt_init_slots(input, MAX_SLOTS);
return 1;
case HID_DG_TIPPRESSURE:
field->logical_minimum = 0;
hid_map_usage(hi, usage, bit, max,
EV_ABS, ABS_MT_PRESSURE);
set_abs(input, ABS_MT_PRESSURE, field, SN_PRESSURE);
/* touchscreen emulation */
input_set_abs_params(hi->input, ABS_PRESSURE,
field->logical_minimum,
field->logical_maximum, 0, 0);
set_abs(input, ABS_PRESSURE, field, SN_PRESSURE);
return 1;
}
return 0;
......@@ -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,
unsigned long **bit, int *max)
{
/* tell hid-input to skip setup of these event types */
if (usage->type == EV_KEY || usage->type == EV_ABS)
clear_bit(usage->code, *bit);
return 0;
set_bit(usage->type, hi->input->evbit);
return -1;
}
/*
......@@ -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)
{
td->first = !td->first; /* touchscreen emulation */
if (td->valid) {
/* emit multitouch events */
input_event(input, EV_ABS, ABS_MT_TRACKING_ID, td->id);
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_mt_slot(input, td->slot);
input_mt_report_slot_state(input, MT_TOOL_FINGER, td->touch);
if (td->touch) {
input_event(input, EV_ABS, ABS_MT_POSITION_X, td->x);
input_event(input, EV_ABS, ABS_MT_POSITION_Y, td->y);
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,
struct hid_usage *usage, __s32 value)
{
......@@ -169,25 +145,26 @@ static int egalax_event(struct hid_device *hid, struct hid_field *field,
* uses a standard parallel multitouch protocol (product ID ==
* 48xx). The second is capacitive and uses an unusual "serial"
* protocol with a different message for each multitouch finger
* (product ID == 72xx). We do not yet generate a correct event
* sequence for the capacitive/serial protocol.
* (product ID == 72xx).
*/
if (hid->claimed & HID_CLAIMED_INPUT) {
struct input_dev *input = field->hidinput->input;
switch (usage->hid) {
case HID_DG_INRANGE:
td->valid = value;
break;
case HID_DG_CONFIDENCE:
/* avoid interference from generic hidinput handling */
break;
case HID_DG_TIPSWITCH:
td->valid = value;
td->touch = value;
break;
case HID_DG_TIPPRESSURE:
td->z = value;
break;
case HID_DG_CONTACTID:
td->id = value;
td->slot = clamp_val(value, 0, MAX_SLOTS - 1);
break;
case HID_GD_X:
td->x = value;
......@@ -195,11 +172,11 @@ static int egalax_event(struct hid_device *hid, struct hid_field *field,
case HID_GD_Y:
td->y = value;
/* this is the last field in a finger */
egalax_filter_event(td, input);
if (td->valid)
egalax_filter_event(td, input);
break;
case HID_DG_CONTACTCOUNT:
/* touch emulation: this is the last field in a frame */
td->first = false;
break;
default:
......@@ -261,6 +238,12 @@ static const struct hid_device_id egalax_devices[] = {
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_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);
......
......@@ -196,6 +196,9 @@
#define USB_DEVICE_ID_EGALAX_TOUCHCONTROLLER 0x0001
#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH 0x480d
#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_DEVICE_ID_ELECOM_BM084 0x0061
......
......@@ -5,7 +5,7 @@
# Each configuration option enables a list of files.
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_POLLDEV) += input-polldev.o
......
......@@ -9,6 +9,8 @@
*
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/module.h>
#include <linux/input.h>
#include <linux/slab.h>
......@@ -23,8 +25,7 @@ static void system_power_event(unsigned int keycode)
switch (keycode) {
case KEY_SUSPEND:
apm_queue_event(APM_USER_SUSPEND);
printk(KERN_INFO "apm-power: Requesting system suspend...\n");
pr_info("Requesting system suspend...\n");
break;
default:
break;
......@@ -65,18 +66,15 @@ static int apmpower_connect(struct input_handler *handler,
error = input_register_handle(handle);
if (error) {
printk(KERN_ERR
"apm-power: Failed to register input power handler, "
"error %d\n", error);
pr_err("Failed to register input power handler, error %d\n",
error);
kfree(handle);
return error;
}
error = input_open_device(handle);
if (error) {
printk(KERN_ERR
"apm-power: Failed to open input power device, "
"error %d\n", error);
pr_err("Failed to open input power device, error %d\n", error);
input_unregister_handle(handle);
kfree(handle);
return error;
......
......@@ -26,6 +26,8 @@
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/input.h>
......@@ -38,8 +40,8 @@ MODULE_LICENSE("GPL");
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",
dev_name(&handle->dev->dev), type, code, value);
printk(KERN_DEBUG pr_fmt("Event. Dev: %s, Type: %d, Code: %d, Value: %d\n"),
dev_name(&handle->dev->dev), type, code, value);
}
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)
goto err_unregister_handle;
printk(KERN_DEBUG "evbug.c: Connected device: %s (%s at %s)\n",
dev_name(&dev->dev),
dev->name ?: "unknown",
dev->phys ?: "unknown");
printk(KERN_DEBUG pr_fmt("Connected device: %s (%s at %s)\n"),
dev_name(&dev->dev),
dev->name ?: "unknown",
dev->phys ?: "unknown");
return 0;
......@@ -80,8 +82,8 @@ static int evbug_connect(struct input_handler *handler, struct input_dev *dev,
static void evbug_disconnect(struct input_handle *handle)
{
printk(KERN_DEBUG "evbug.c: Disconnected device: %s\n",
dev_name(&handle->dev->dev));
printk(KERN_DEBUG pr_fmt("Disconnected device: %s\n"),
dev_name(&handle->dev->dev));
input_close_device(handle);
input_unregister_handle(handle);
......
......@@ -8,6 +8,8 @@
* the Free Software Foundation.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#define EVDEV_MINOR_BASE 64
#define EVDEV_MINORS 32
#define EVDEV_MIN_BUFFER_SIZE 64U
......@@ -522,12 +524,11 @@ static int handle_eviocgbit(struct input_dev *dev,
if (type == EV_KEY && size == OLD_KEY_MAX) {
len = OLD_KEY_MAX;
if (printk_timed_ratelimit(&keymax_warn_time, 10 * 1000))
printk(KERN_WARNING
"evdev.c(EVIOCGBIT): Suspicious buffer size %u, "
"limiting output to %zu bytes. See "
"http://userweb.kernel.org/~dtor/eviocgbit-bug.html\n",
OLD_KEY_MAX,
BITS_TO_LONGS(OLD_KEY_MAX) * sizeof(long));
pr_warning("(EVIOCGBIT): Suspicious buffer size %u, "
"limiting output to %zu bytes. See "
"http://userweb.kernel.org/~dtor/eviocgbit-bug.html\n",
OLD_KEY_MAX,
BITS_TO_LONGS(OLD_KEY_MAX) * sizeof(long));
}
return bits_to_user(bits, len, size, p, compat_mode);
......@@ -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))
switch (EVIOC_MASK_SIZE(cmd)) {
case EVIOCGPROP(0):
return bits_to_user(dev->propbit, INPUT_PROP_MAX,
size, p, compat_mode);
case EVIOCGKEY(0):
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,
break;
if (minor == EVDEV_MINORS) {
printk(KERN_ERR "evdev: no more free evdev devices\n");
pr_err("no more free evdev devices\n");
return -ENFILE;
}
......
......@@ -23,7 +23,7 @@
/* #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/module.h>
......@@ -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 ||
!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;
}
......@@ -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_MAX ||
!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;
}
......@@ -246,7 +246,7 @@ static int flush_effects(struct input_dev *dev, struct file *file)
struct ff_device *ff = dev->ff;
int i;
debug("flushing now");
pr_debug("flushing now\n");
mutex_lock(&ff->mutex);
......@@ -315,8 +315,7 @@ int input_ff_create(struct input_dev *dev, int max_effects)
int i;
if (!max_effects) {
printk(KERN_ERR
"ff-core: cannot allocate device without any effects\n");
pr_err("cannot allocate device without any effects\n");
return -EINVAL;
}
......
......@@ -23,7 +23,7 @@
/* #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/input.h>
......@@ -129,7 +129,7 @@ static void ml_schedule_timer(struct ml_device *ml)
int events = 0;
int i;
debug("calculating next timer");
pr_debug("calculating next timer\n");
for (i = 0; i < FF_MEMLESS_EFFECTS; i++) {
......@@ -149,10 +149,10 @@ static void ml_schedule_timer(struct ml_device *ml)
}
if (!events) {
debug("no actions");
pr_debug("no actions\n");
del_timer(&ml->timer);
} else {
debug("timer set");
pr_debug("timer set\n");
mod_timer(&ml->timer, earliest);
}
}
......@@ -173,8 +173,8 @@ static int apply_envelope(struct ml_effect_state *state, int value,
if (envelope->attack_length &&
time_before(now,
state->play_at + msecs_to_jiffies(envelope->attack_length))) {
debug("value = 0x%x, attack_level = 0x%x", value,
envelope->attack_level);
pr_debug("value = 0x%x, attack_level = 0x%x\n",
value, envelope->attack_level);
time_from_level = jiffies_to_msecs(now - state->play_at);
time_of_envelope = envelope->attack_length;
envelope_level = min_t(__s16, envelope->attack_level, 0x7fff);
......@@ -191,13 +191,13 @@ static int apply_envelope(struct ml_effect_state *state, int value,
difference = abs(value) - envelope_level;
debug("difference = %d", difference);
debug("time_from_level = 0x%x", time_from_level);
debug("time_of_envelope = 0x%x", time_of_envelope);
pr_debug("difference = %d\n", difference);
pr_debug("time_from_level = 0x%x\n", time_from_level);
pr_debug("time_of_envelope = 0x%x\n", time_of_envelope);
difference = difference * time_from_level / time_of_envelope;
debug("difference = %d", difference);
pr_debug("difference = %d\n", difference);
return value < 0 ?
-(difference + envelope_level) : (difference + envelope_level);
......@@ -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))
return FF_RUMBLE;
printk(KERN_ERR
"ff-memless: invalid type in get_compatible_type()\n");
pr_err("invalid type in get_compatible_type()\n");
return 0;
}
......@@ -312,7 +311,7 @@ static void ml_combine_effects(struct ff_effect *effect,
break;
default:
printk(KERN_ERR "ff-memless: invalid type in ml_combine_effects()\n");
pr_err("invalid type in ml_combine_effects()\n");
break;
}
......@@ -406,7 +405,7 @@ static void ml_effect_timer(unsigned long timer_data)
struct ml_device *ml = dev->ff->private;
unsigned long flags;
debug("timer: updating effects");
pr_debug("timer: updating effects\n");
spin_lock_irqsave(&dev->event_lock, flags);
ml_play_effects(ml);
......@@ -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];
if (value > 0) {
debug("initiated play");
pr_debug("initiated play\n");
__set_bit(FF_EFFECT_STARTED, &state->flags);
state->count = 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;
} else {
debug("initiated stop");
pr_debug("initiated stop\n");
if (test_bit(FF_EFFECT_PLAYING, &state->flags))
__set_bit(FF_EFFECT_ABORTING, &state->flags);
......
......@@ -18,13 +18,11 @@
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/gameport.h>
#include <linux/wait.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/kthread.h>
#include <linux/workqueue.h>
#include <linux/sched.h> /* HZ */
#include <linux/mutex.h>
#include <linux/freezer.h>
/*#include <asm/io.h>*/
......@@ -234,58 +232,22 @@ struct gameport_event {
static DEFINE_SPINLOCK(gameport_event_lock); /* protects 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,
enum gameport_event_type event_type)
static struct gameport_event *gameport_get_event(void)
{
struct gameport_event *event = NULL;
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 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;
if (!list_empty(&gameport_event_list)) {
event = list_first_entry(&gameport_event_list,
struct gameport_event, node);
list_del_init(&event->node);
}
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);
return retval;
return event;
}
static void gameport_free_event(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);
}
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;
......@@ -368,6 +314,59 @@ static void gameport_handle_event(void)
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,
* be it a gameport port or a driver.
......@@ -419,19 +418,6 @@ static struct gameport *gameport_get_pending_child(struct gameport *parent)
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
*/
......@@ -814,13 +800,6 @@ static int __init gameport_init(void)
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;
}
......@@ -828,7 +807,12 @@ static int __init gameport_init(void)
static void __exit gameport_exit(void)
{
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);
......
/*
* 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 @@
* the Free Software Foundation.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/jiffies.h>
#include <linux/slab.h>
#include <linux/mutex.h>
......@@ -33,8 +35,7 @@ static int input_polldev_start_workqueue(void)
if (!polldev_users) {
polldev_wq = create_singlethread_workqueue("ipolldevd");
if (!polldev_wq) {
printk(KERN_ERR "input-polldev: failed to create "
"ipolldevd workqueue\n");
pr_err("failed to create ipolldevd workqueue\n");
retval = -ENOMEM;
goto out;
}
......
......@@ -10,9 +10,11 @@
* the Free Software Foundation.
*/
#define pr_fmt(fmt) KBUILD_BASENAME ": " fmt
#include <linux/init.h>
#include <linux/types.h>
#include <linux/input.h>
#include <linux/input/mt.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/random.h>
......@@ -959,10 +961,8 @@ static int input_attach_handler(struct input_dev *dev, struct input_handler *han
error = handler->connect(handler, dev, id);
if (error && error != -ENODEV)
printk(KERN_ERR
"input: failed to attach handler %s to device %s, "
"error: %d\n",
handler->name, kobject_name(&dev->dev.kobj), error);
pr_err("failed to attach handler %s to device %s, error: %d\n",
handler->name, kobject_name(&dev->dev.kobj), error);
return error;
}
......@@ -1110,6 +1110,8 @@ static int input_devices_seq_show(struct seq_file *seq, void *v)
seq_printf(seq, "%s ", handle->name);
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);
if (test_bit(EV_KEY, dev->evbit))
input_seq_print_bitmap(seq, "KEY", dev->keybit, KEY_MAX);
......@@ -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 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[] = {
&dev_attr_name.attr,
&dev_attr_phys.attr,
&dev_attr_uniq.attr,
&dev_attr_modalias.attr,
&dev_attr_properties.attr,
NULL
};
......@@ -1471,7 +1488,7 @@ static int input_add_uevent_bm_var(struct kobj_uevent_env *env,
{
int len;
if (add_uevent_var(env, "%s=", name))
if (add_uevent_var(env, "%s", name))
return -ENOMEM;
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)
if (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);
if (test_bit(EV_KEY, dev->evbit))
INPUT_ADD_HOTPLUG_BM_VAR("KEY=", dev->keybit, KEY_MAX);
......@@ -1725,52 +1744,6 @@ void input_free_device(struct input_dev *dev)
}
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
* @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
break;
default:
printk(KERN_ERR
"input_set_capability: unknown type %u (code %u)\n",
type, code);
pr_err("input_set_capability: unknown type %u (code %u)\n",
type, code);
dump_stack();
return;
}
......@@ -1904,8 +1876,9 @@ int input_register_device(struct input_dev *dev)
return error;
path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL);
printk(KERN_INFO "input: %s as %s\n",
dev->name ? dev->name : "Unspecified device", path ? path : "N/A");
pr_info("%s as %s\n",
dev->name ? dev->name : "Unspecified device",
path ? path : "N/A");
kfree(path);
error = mutex_lock_interruptible(&input_mutex);
......@@ -2187,7 +2160,7 @@ static int __init input_init(void)
err = class_register(&input_class);
if (err) {
printk(KERN_ERR "input: unable to register input_dev class\n");
pr_err("unable to register input_dev class\n");
return err;
}
......@@ -2197,7 +2170,7 @@ static int __init input_init(void)
err = register_chrdev(INPUT_MAJOR, "input", &input_fops);
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;
}
......
......@@ -10,6 +10,8 @@
* (at your option) any later version.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <asm/io.h>
#include <asm/system.h>
#include <linux/delay.h>
......@@ -806,7 +808,7 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev,
break;
if (minor == JOYDEV_MINORS) {
printk(KERN_ERR "joydev: no more free joydev devices\n");
pr_err("no more free joydev devices\n");
return -ENFILE;
}
......
......@@ -4,17 +4,8 @@
# 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
ifeq ($(CONFIG_JOYSTICK_IFORCE_232),y)
iforce-objs += iforce-serio.o
endif
ifeq ($(CONFIG_JOYSTICK_IFORCE_USB),y)
iforce-objs += iforce-usb.o
endif
EXTRA_CFLAGS = -Werror-implicit-function-declaration
iforce-y := iforce-ff.o iforce-main.o iforce-packets.o
iforce-$(CONFIG_JOYSTICK_IFORCE_232) += iforce-serio.o
iforce-$(CONFIG_JOYSTICK_IFORCE_USB) += iforce-usb.o
......@@ -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)
{
struct usb_endpoint_descriptor *ep_irq_out;
int error = -ENOMEM;
int error;
if (xpad->xtype != XTYPE_XBOX360 && xpad->xtype != XTYPE_XBOX)
return 0;
xpad->odata = usb_alloc_coherent(xpad->udev, XPAD_PKT_LEN,
GFP_KERNEL, &xpad->odata_dma);
if (!xpad->odata)
if (!xpad->odata) {
error = -ENOMEM;
goto fail1;
}
mutex_init(&xpad->odata_mutex);
xpad->irq_out = usb_alloc_urb(0, GFP_KERNEL);
if (!xpad->irq_out)
if (!xpad->irq_out) {
error = -ENOMEM;
goto fail2;
}
ep_irq_out = &intf->cur_altsetting->endpoint[1].desc;
usb_fill_int_urb(xpad->irq_out, xpad->udev,
......@@ -728,7 +732,7 @@ static void xpad_led_disconnect(struct usb_xpad *xpad)
if (xpad_led) {
led_classdev_unregister(&xpad_led->led_cdev);
kfree(xpad_led->name);
kfree(xpad_led);
}
}
#else
......@@ -756,8 +760,9 @@ static void xpad_close(struct input_dev *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);
xpad_stop_output(xpad);
}
......@@ -789,8 +794,7 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
struct usb_xpad *xpad;
struct input_dev *input_dev;
struct usb_endpoint_descriptor *ep_irq_in;
int i;
int error = -ENOMEM;
int i, error;
for (i = 0; xpad_device[i].idVendor; i++) {
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
xpad = kzalloc(sizeof(struct usb_xpad), GFP_KERNEL);
input_dev = input_allocate_device();
if (!xpad || !input_dev)
if (!xpad || !input_dev) {
error = -ENOMEM;
goto fail1;
}
xpad->idata = usb_alloc_coherent(udev, XPAD_PKT_LEN,
GFP_KERNEL, &xpad->idata_dma);
if (!xpad->idata)
if (!xpad->idata) {
error = -ENOMEM;
goto fail1;
}
xpad->irq_in = usb_alloc_urb(0, GFP_KERNEL);
if (!xpad->irq_in)
if (!xpad->irq_in) {
error = -ENOMEM;
goto fail2;
}
xpad->udev = udev;
xpad->mapping = xpad_device[i].mapping;
......@@ -887,15 +897,15 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
error = xpad_init_output(intf, xpad);
if (error)
goto fail2;
goto fail3;
error = xpad_init_ff(xpad);
if (error)
goto fail3;
goto fail4;
error = xpad_led_probe(xpad);
if (error)
goto fail3;
goto fail5;
ep_irq_in = &intf->cur_altsetting->endpoint[0].desc;
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
error = input_register_device(xpad->dev);
if (error)
goto fail4;
goto fail6;
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) {
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
* controller when it shows up
*/
xpad->bulk_out = usb_alloc_urb(0, GFP_KERNEL);
if(!xpad->bulk_out)
goto fail5;
if (!xpad->bulk_out) {
error = -ENOMEM;
goto fail7;
}
xpad->bdata = kzalloc(XPAD_PKT_LEN, GFP_KERNEL);
if(!xpad->bdata)
goto fail6;
if (!xpad->bdata) {
error = -ENOMEM;
goto fail8;
}
xpad->bdata[2] = 0x08;
switch (intf->cur_altsetting->desc.bInterfaceNumber) {
......@@ -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_sndbulkpipe(udev, ep_irq_in->bEndpointAddress),
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;
fail6: usb_free_urb(xpad->bulk_out);
fail5: usb_kill_urb(xpad->irq_in);
fail4: usb_free_urb(xpad->irq_in);
fail3: xpad_deinit_output(xpad);
fail9: kfree(xpad->bdata);
fail8: usb_free_urb(xpad->bulk_out);
fail7: input_unregister_device(input_dev);
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);
fail1: input_free_device(input_dev);
kfree(xpad);
......@@ -974,21 +993,24 @@ static void xpad_disconnect(struct usb_interface *intf)
{
struct usb_xpad *xpad = usb_get_intfdata (intf);
usb_set_intfdata(intf, NULL);
if (xpad) {
xpad_led_disconnect(xpad);
input_unregister_device(xpad->dev);
xpad_deinit_output(xpad);
if (xpad->xtype == XTYPE_XBOX360W) {
usb_kill_urb(xpad->bulk_out);
usb_free_urb(xpad->bulk_out);
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);
xpad_led_disconnect(xpad);
input_unregister_device(xpad->dev);
xpad_deinit_output(xpad);
if (xpad->xtype == XTYPE_XBOX360W) {
usb_kill_urb(xpad->bulk_out);
usb_free_urb(xpad->bulk_out);
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->bdata);
kfree(xpad);
usb_set_intfdata(intf, NULL);
}
static struct usb_driver xpad_driver = {
......@@ -1000,10 +1022,7 @@ static struct usb_driver xpad_driver = {
static int __init usb_xpad_init(void)
{
int result = usb_register(&xpad_driver);
if (result == 0)
printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_DESC "\n");
return result;
return usb_register(&xpad_driver);
}
static void __exit usb_xpad_exit(void)
......
......@@ -196,20 +196,22 @@ config KEYBOARD_GPIO_POLLED
module will be called gpio_keys_polled.
config KEYBOARD_TCA6416
tristate "TCA6416 Keypad Support"
tristate "TCA6416/TCA6408A Keypad Support"
depends on I2C
help
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
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
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.
To compile this driver as a module, choose M here: the
module will be called tca6416_keypad.
config KEYBOARD_MATRIX
tristate "GPIO driven matrix keypad support"
......@@ -459,6 +461,15 @@ config KEYBOARD_OMAP4
To compile this driver as a module, choose M here: the
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
tristate "TI TNETV107X keypad support"
depends on ARCH_DAVINCI_TNETV107X
......
......@@ -38,6 +38,7 @@ obj-$(CONFIG_KEYBOARD_PXA930_ROTARY) += pxa930_rotary.o
obj-$(CONFIG_KEYBOARD_QT2160) += qt2160.o
obj-$(CONFIG_KEYBOARD_SAMSUNG) += samsung-keypad.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_STOWAWAY) += stowaway.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 @@
static const struct i2c_device_id tca6416_id[] = {
{ "tca6416-keys", 16, },
{ "tca6408-keys", 8, },
{ }
};
MODULE_DEVICE_TABLE(i2c, tca6416_id);
......@@ -46,8 +47,9 @@ struct tca6416_keypad_chip {
struct i2c_client *client;
struct input_dev *input;
struct delayed_work dwork;
u16 pinmask;
int io_size;
int irqnum;
u16 pinmask;
bool use_polling;
struct tca6416_button buttons[0];
};
......@@ -56,7 +58,9 @@ static int tca6416_write_reg(struct tca6416_keypad_chip *chip, int reg, u16 val)
{
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) {
dev_err(&chip->client->dev,
"%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)
{
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) {
dev_err(&chip->client->dev, "%s failed, reg: %d, error: %d\n",
__func__, reg, retval);
......@@ -224,6 +230,7 @@ static int __devinit tca6416_keypad_probe(struct i2c_client *client,
chip->client = client;
chip->input = input;
chip->io_size = id->driver_data;
chip->pinmask = pdata->pinmask;
chip->use_polling = pdata->use_polling;
......
......@@ -448,4 +448,28 @@ config INPUT_ADXL34X_SPI
To compile this driver as a module, choose M here: the
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
......@@ -18,6 +18,8 @@ obj-$(CONFIG_INPUT_ATI_REMOTE2) += ati_remote2.o
obj-$(CONFIG_INPUT_ATLAS_BTNS) += atlas_btns.o
obj-$(CONFIG_INPUT_BFIN_ROTARY) += bfin_rotary.o
obj-$(CONFIG_INPUT_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_DM355EVM) += dm355evm_keys.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)
}
#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);
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);
return 0;
}
static const struct dev_pm_ops pcf8574_kp_pm_ops = {
.suspend = pcf8574_kp_suspend,
.resume = pcf8574_kp_resume,
};
#else
# define pcf8574_kp_resume NULL
# define pcf8574_kp_suspend NULL
......@@ -197,11 +207,12 @@ static struct i2c_driver pcf8574_kp_driver = {
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
#ifdef CONFIG_PM
.pm = &pcf8574_kp_pm_ops,
#endif
},
.probe = pcf8574_kp_probe,
.remove = __devexit_p(pcf8574_kp_remove),
.suspend = pcf8574_kp_suspend,
.resume = pcf8574_kp_resume,
.id_table = pcf8574_kp_id,
};
......
......@@ -37,6 +37,7 @@
#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <linux/uinput.h>
#include <linux/input/mt.h>
#include "../input-compat.h"
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
goto exit;
if (test_bit(ABS_MT_SLOT, dev->absbit)) {
int nslot = input_abs_get_max(dev, ABS_MT_SLOT) + 1;
input_mt_create_slots(dev, nslot);
input_set_events_per_packet(dev, 6 * nslot);
input_mt_init_slots(dev, nslot);
} else if (test_bit(ABS_MT_POSITION_X, dev->absbit)) {
input_set_events_per_packet(dev, 60);
}
......@@ -680,6 +680,10 @@ static long uinput_ioctl_handler(struct file *file, unsigned int cmd,
retval = uinput_set_bit(arg, swbit, SW_MAX);
break;
case UI_SET_PROPBIT:
retval = uinput_set_bit(arg, propbit, INPUT_PROP_MAX);
break;
case UI_SET_PHYS:
if (udev->state == UIST_CREATED) {
retval = -EINVAL;
......
This diff is collapsed.
......@@ -5,6 +5,9 @@
#ifndef _HGPK_H
#define _HGPK_H
#define HGPK_GS 0xff /* The GlideSensor */
#define HGPK_PT 0xcf /* The PenTablet */
enum hgpk_model_t {
HGPK_MODEL_PREA = 0x0a, /* pre-B1s */
HGPK_MODEL_A = 0x14, /* found on B1s, PT disabled in hardware */
......@@ -13,12 +16,34 @@ enum hgpk_model_t {
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 psmouse *psmouse;
enum hgpk_mode mode;
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;
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...) \
......@@ -33,9 +58,13 @@ struct hgpk_data {
dev_notice(&(psmouse)->ps2dev.serio->dev, format, ## arg)
#ifdef CONFIG_MOUSE_PS2_OLPC
void hgpk_module_init(void);
int hgpk_detect(struct psmouse *psmouse, bool set_properties);
int hgpk_init(struct psmouse *psmouse);
#else
static inline void hgpk_module_init(void)
{
}
static inline int hgpk_detect(struct psmouse *psmouse, bool set_properties)
{
return -ENODEV;
......
......@@ -1711,6 +1711,7 @@ static int __init psmouse_init(void)
lifebook_module_init();
synaptics_module_init();
hgpk_module_init();
kpsmoused_wq = create_singlethread_workqueue("kpsmoused");
if (!kpsmoused_wq) {
......
......@@ -25,7 +25,7 @@
#include <linux/module.h>
#include <linux/dmi.h>
#include <linux/input.h>
#include <linux/input/mt.h>
#include <linux/serio.h>
#include <linux/libps2.h>
#include <linux/slab.h>
......@@ -279,6 +279,25 @@ static void synaptics_set_rate(struct psmouse *psmouse, unsigned int rate)
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
****************************************************************************/
......@@ -380,7 +399,9 @@ static void synaptics_pt_create(struct psmouse *psmouse)
* 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));
......@@ -397,6 +418,14 @@ static void synaptics_parse_hw_state(unsigned char buf[], struct synaptics_data
((buf[0] & 0x04) >> 1) |
((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->right = (buf[0] & 0x02) ? 1 : 0;
......@@ -452,6 +481,36 @@ static void synaptics_parse_hw_state(unsigned char buf[], struct synaptics_data
hw->left = (buf[0] & 0x01) ? 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)
int finger_width;
int i;
synaptics_parse_hw_state(psmouse->packet, priv, &hw);
if (synaptics_parse_hw_state(psmouse->packet, priv, &hw))
return;
if (hw.scroll) {
priv->scroll += hw.scroll;
......@@ -488,7 +548,7 @@ static void synaptics_process_packet(struct psmouse *psmouse)
return;
}
if (hw.z > 0) {
if (hw.z > 0 && hw.x > 1) {
num_fingers = 1;
finger_width = 5;
if (SYN_CAP_EXTENDED(priv->capabilities)) {
......@@ -512,6 +572,9 @@ static void synaptics_process_packet(struct psmouse *psmouse)
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
* BTN_TOUCH has to be first as mousedev relies on it when doing
* absolute -> relative conversion
......@@ -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 < 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_Y, YMAX_NOMINAL + YMIN_NOMINAL - hw.y);
}
......@@ -622,6 +685,8 @@ static void set_input_params(struct input_dev *dev, struct synaptics_data *priv)
{
int i;
__set_bit(INPUT_PROP_POINTER, dev->propbit);
__set_bit(EV_ABS, dev->evbit);
input_set_abs_params(dev, ABS_X,
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)
YMIN_NOMINAL, priv->y_max ?: YMAX_NOMINAL, 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))
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)
input_abs_set_res(dev, ABS_Y, priv->y_res);
if (SYN_CAP_CLICKPAD(priv->ext_cap_0c)) {
__set_bit(INPUT_PROP_BUTTONPAD, dev->propbit);
/* Clickpads report only left button */
__clear_bit(BTN_RIGHT, dev->keybit);
__clear_bit(BTN_MIDDLE, dev->keybit);
......@@ -702,6 +777,11 @@ static int synaptics_reconnect(struct psmouse *psmouse)
return -1;
}
if (synaptics_set_advanced_gesture_mode(psmouse)) {
printk(KERN_ERR "Advanced gesture mode reconnect failed.\n");
return -1;
}
return 0;
}
......@@ -744,15 +824,45 @@ static const struct dmi_system_id __initconst toshiba_dmi_table[] = {
#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)
{
impaired_toshiba_kbc = dmi_check_system(toshiba_dmi_table);
broken_olpc_ec = dmi_check_system(olpc_dmi_table);
}
int synaptics_init(struct psmouse *psmouse)
{
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);
if (!priv)
return -ENOMEM;
......@@ -769,6 +879,11 @@ int synaptics_init(struct psmouse *psmouse)
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;
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)
/*
* Toshiba's KBC seems to have trouble handling data from
* Synaptics as full rate, switch to lower rate which is roughly
* thye same as rate of standard PS/2 mouse.
* Synaptics at full rate. Switch to a lower rate (roughly
* the same rate as a standard PS/2 mouse).
*/
if (psmouse->rate >= 80 && impaired_toshiba_kbc) {
printk(KERN_INFO "synaptics: Toshiba %s detected, limiting rate to 40pps.\n",
......
......@@ -54,6 +54,7 @@
#define SYN_CAP_CLICKPAD(ex0c) ((ex0c) & 0x100000) /* 1-button ClickPad */
#define SYN_CAP_CLICKPAD2BTN(ex0c) ((ex0c) & 0x000100) /* 2-button ClickPad */
#define SYN_CAP_MAX_DIMENSIONS(ex0c) ((ex0c) & 0x020000)
#define SYN_CAP_ADV_GESTURE(ex0c) ((ex0c) & 0x080000)
/* synaptics modes query bits */
#define SYN_MODE_ABSOLUTE(m) ((m) & (1 << 7))
......@@ -113,6 +114,8 @@ struct synaptics_data {
int scroll;
struct serio *pt_port; /* Pass-through serio port */
struct synaptics_hw_state mt; /* current gesture packet */
};
void synaptics_module_init(void);
......
......@@ -9,6 +9,8 @@
* the Free Software Foundation.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#define MOUSEDEV_MINOR_BASE 32
#define MOUSEDEV_MINORS 32
#define MOUSEDEV_MIX 31
......@@ -977,7 +979,7 @@ static int mousedev_connect(struct input_handler *handler,
break;
if (minor == MOUSEDEV_MINORS) {
printk(KERN_ERR "mousedev: no more free mousedev devices\n");
pr_err("no more free mousedev devices\n");
return -ENFILE;
}
......@@ -1087,13 +1089,13 @@ static int __init mousedev_init(void)
#ifdef CONFIG_INPUT_MOUSEDEV_PSAUX
error = misc_register(&psaux_mouse);
if (error)
printk(KERN_WARNING "mice: could not register psaux device, "
"error: %d\n", error);
pr_warning("could not register psaux device, error: %d\n",
error);
else
psaux_registered = 1;
#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;
}
......
......@@ -172,6 +172,5 @@ static void __exit ams_delta_serio_exit(void)
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_DATA);
kfree(ams_delta_serio);
}
module_exit(ams_delta_serio_exit);
......@@ -191,6 +191,9 @@ static int __devinit ct82c710_probe(struct platform_device *dev)
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;
}
......@@ -237,11 +240,6 @@ static int __init ct82c710_init(void)
if (error)
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;
err_free_device:
......
......@@ -932,6 +932,11 @@ int hil_mlc_register(hil_mlc *mlc)
hil_mlc_copy_di_scratch(mlc, i);
mlc_serio = kzalloc(sizeof(*mlc_serio), GFP_KERNEL);
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->phys, sizeof(mlc_serio->phys)-1, "HIL%d", i);
mlc_serio->id = hil_mlc_serio_id;
......
......@@ -305,6 +305,7 @@ static void hp_sdc_mlc_out(hil_mlc *mlc)
static int __init hp_sdc_mlc_init(void)
{
hil_mlc *mlc = &hp_sdc_mlc;
int err;
#ifdef __mc68000__
if (!MACH_IS_HP300)
......@@ -323,22 +324,21 @@ static int __init hp_sdc_mlc_init(void)
mlc->out = &hp_sdc_mlc_out;
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");
goto err0;
return err;
}
if (hp_sdc_request_hil_irq(&hp_sdc_mlc_isr)) {
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;
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)
......
......@@ -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.
*/
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 */
.matches = {
......@@ -752,7 +759,7 @@ static int __init i8042_pnp_init(void)
#endif
if (i8042_nopnp) {
printk(KERN_INFO "i8042: PNP detection disabled\n");
pr_info("PNP detection disabled\n");
return 0;
}
......@@ -769,7 +776,7 @@ static int __init i8042_pnp_init(void)
#if defined(__ia64__)
return -ENODEV;
#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;
#endif
}
......@@ -781,7 +788,7 @@ static int __init i8042_pnp_init(void)
snprintf(aux_irq_str, sizeof(aux_irq_str),
"%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_aux_name,
i8042_pnp_data_reg, i8042_pnp_command_reg,
......@@ -798,9 +805,7 @@ static int __init i8042_pnp_init(void)
if (((i8042_pnp_data_reg & ~0xf) == (i8042_data_reg & ~0xf) &&
i8042_pnp_data_reg != i8042_data_reg) ||
!i8042_pnp_data_reg) {
printk(KERN_WARNING
"PNP: PS/2 controller has invalid data port %#x; "
"using default %#x\n",
pr_warn("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;
pnp_data_busted = true;
......@@ -809,33 +814,27 @@ static int __init i8042_pnp_init(void)
if (((i8042_pnp_command_reg & ~0xf) == (i8042_command_reg & ~0xf) &&
i8042_pnp_command_reg != i8042_command_reg) ||
!i8042_pnp_command_reg) {
printk(KERN_WARNING
"PNP: PS/2 controller has invalid command port %#x; "
"using default %#x\n",
pr_warn("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;
pnp_data_busted = true;
}
if (!i8042_nokbd && !i8042_pnp_kbd_irq) {
printk(KERN_WARNING
"PNP: PS/2 controller doesn't have KBD irq; "
"using default %d\n", i8042_kbd_irq);
pr_warn("PNP: PS/2 controller doesn't have KBD irq; using default %d\n",
i8042_kbd_irq);
i8042_pnp_kbd_irq = i8042_kbd_irq;
pnp_data_busted = true;
}
if (!i8042_noaux && !i8042_pnp_aux_irq) {
if (!pnp_data_busted && i8042_pnp_kbd_irq) {
printk(KERN_WARNING
"PNP: PS/2 appears to have AUX port disabled, "
"if this is incorrect please boot with "
"i8042.nopnp\n");
pr_warn("PNP: PS/2 appears to have AUX port disabled, "
"if this is incorrect please boot with i8042.nopnp\n");
i8042_noaux = true;
} else {
printk(KERN_WARNING
"PNP: PS/2 controller doesn't have AUX irq; "
"using default %d\n", i8042_aux_irq);
pr_warn("PNP: PS/2 controller doesn't have AUX irq; using default %d\n",
i8042_aux_irq);
i8042_pnp_aux_irq = i8042_aux_irq;
}
}
......
This diff is collapsed.
......@@ -89,15 +89,19 @@
#ifdef DEBUG
static unsigned long i8042_start_time;
#define dbg_init() do { i8042_start_time = jiffies; } while (0)
#define dbg(format, arg...) \
do { \
#define dbg(format, arg...) \
do { \
if (i8042_debug) \
printk(KERN_DEBUG __FILE__ ": " format " [%d]\n" , \
## arg, (int) (jiffies - i8042_start_time)); \
printk(KERN_DEBUG KBUILD_MODNAME ": [%d] " format, \
(int) (jiffies - i8042_start_time), ##arg); \
} while (0)
#else
#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 /* _I8042_H */
......@@ -207,7 +207,7 @@ static int ps2mult_connect(struct serio *serio, struct serio_driver *drv)
err_out:
while (--i >= 0)
kfree(psm->ports[i].serio);
kfree(serio);
kfree(psm);
return error;
}
......
......@@ -32,10 +32,9 @@
#include <linux/module.h>
#include <linux/serio.h>
#include <linux/errno.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/kthread.h>
#include <linux/workqueue.h>
#include <linux/mutex.h>
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
......@@ -44,7 +43,7 @@ MODULE_LICENSE("GPL");
/*
* 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);
......@@ -165,58 +164,22 @@ struct serio_event {
static DEFINE_SPINLOCK(serio_event_lock); /* protects 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,
enum serio_event_type event_type)
static struct serio_event *serio_get_event(void)
{
struct serio_event *event = NULL;
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;
if (!list_empty(&serio_event_list)) {
event = list_first_entry(&serio_event_list,
struct serio_event, node);
list_del_init(&event->node);
}
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);
return retval;
return event;
}
static void serio_free_event(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);
}
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)
static void serio_handle_event(struct work_struct *work)
{
struct serio_event *event;
......@@ -307,6 +252,59 @@ static void serio_handle_event(void)
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
* object, be it serio port or driver.
......@@ -356,18 +354,6 @@ static struct serio *serio_get_pending_child(struct serio *parent)
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
*/
......@@ -1040,21 +1026,18 @@ static int __init serio_init(void)
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;
}
static void __exit serio_exit(void)
{
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);
......
......@@ -14,6 +14,7 @@
#include "wacom_wac.h"
#include "wacom.h"
#include <linux/input/mt.h>
static int wacom_penpartner_irq(struct wacom_wac *wacom)
{
......@@ -862,19 +863,21 @@ static int wacom_bpt_touch(struct wacom_wac *wacom)
struct wacom_features *features = &wacom->features;
struct input_dev *input = wacom->input;
unsigned char *data = wacom->data;
int sp = 0, sx = 0, sy = 0, count = 0;
int i;
for (i = 0; i < 2; i++) {
int p = data[9 * i + 2];
bool touch = p && !wacom->shared->stylus_in_proximity;
input_mt_slot(input, i);
input_mt_report_slot_state(input, MT_TOOL_FINGER, touch);
/*
* Touch events need to be disabled while stylus is
* in proximity because user's hand is resting on touchpad
* and sending unwanted events. User expects tablet buttons
* to continue working though.
*/
if (p && !wacom->shared->stylus_in_proximity) {
if (touch) {
int x = get_unaligned_be16(&data[9 * i + 3]) & 0x7ff;
int y = get_unaligned_be16(&data[9 * i + 5]) & 0x7ff;
if (features->quirks & WACOM_QUIRK_BBTOUCH_LOWRES) {
......@@ -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_POSITION_X, x);
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_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_mt_report_pointer_emulation(input, true);
input_report_key(input, BTN_LEFT, (data[1] & 0x08) != 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,
__set_bit(BTN_TOOL_FINGER, 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,
0, features->x_max,
features->x_fuzz, 0);
......@@ -1282,8 +1272,6 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev,
input_set_abs_params(input_dev, ABS_MT_PRESSURE,
0, features->pressure_max,
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) {
__set_bit(BTN_TOOL_RUBBER, input_dev->keybit);
__set_bit(BTN_TOOL_PEN, input_dev->keybit);
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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