2
0
mirror of https://github.com/edk2-porting/linux-next.git synced 2024-11-19 16:14:13 +08:00

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

Pull input layer updates from Dmitry Torokhov:
 - a bunch of new drivers (DA9052/53 touchscreenn controller, Synaptics
   Navpoint, LM8333 keypads, Wacom I2C touhscreen);
 - updates to existing touchpad drivers (ALPS, Sntelic);
 - Wacom driver now supports Intuos5;
 - device-tree bindings in numerous drivers;
 - other cleanups and fixes.

Fix annoying conflict in drivers/input/tablet/wacom_wac.c that I think
implies that the input layer device naming is broken, but let's see.  I
brough it up with Dmitry.

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input: (57 commits)
  Input: matrix-keymap - fix building keymaps
  Input: spear-keyboard - document DT bindings
  Input: spear-keyboard - add device tree bindings
  Input: matrix-keymap - wire up device tree support
  Input: matrix-keymap - uninline and prepare for device tree support
  Input: adp5588 - add support for gpio names
  Input: omap-keypad - dynamically handle register offsets
  Input: synaptics - fix compile warning
  MAINTAINERS: adjust input-related patterns
  Input: ALPS - switch to using input_mt_report_finger_count
  Input: ALPS - add semi-MT support for v4 protocol
  Input: Add Synaptics NavPoint (PXA27x SSP/SPI) driver
  Input: atmel_mxt_ts - dump each message on just 1 line
  Input: atmel_mxt_ts - do not read extra (checksum) byte
  Input: atmel_mxt_ts - verify object size in mxt_write_object
  Input: atmel_mxt_ts - only allow root to update firmware
  Input: atmel_mxt_ts - use CONFIG_PM_SLEEP
  Input: sentelic - report device's production serial number
  Input: tl6040-vibra - Device Tree support
  Input: evdev - properly handle read/write with count 0
  ...
This commit is contained in:
Linus Torvalds 2012-05-24 10:34:29 -07:00
commit 2c01e7bc46
106 changed files with 2848 additions and 1308 deletions

View File

@ -23,9 +23,10 @@ Contact: linux-input@vger.kernel.org
Description:
Attribute group for control of the status LEDs and the OLEDs.
This attribute group is only available for Intuos 4 M, L,
and XL (with LEDs and OLEDs) and Cintiq 21UX2 and Cintiq 24HD
(LEDs only). Therefore its presence implicitly signifies the
presence of said LEDs and OLEDs on the tablet device.
and XL (with LEDs and OLEDs), Intuos 5 (LEDs only), and Cintiq
21UX2 and Cintiq 24HD (LEDs only). Therefore its presence
implicitly signifies the presence of said LEDs and OLEDs on the
tablet device.
What: /sys/bus/usb/devices/<busnum>-<devnum>:<cfg>.<intf>/wacom_led/status0_luminance
Date: August 2011
@ -48,10 +49,10 @@ What: /sys/bus/usb/devices/<busnum>-<devnum>:<cfg>.<intf>/wacom_led/status_led0
Date: August 2011
Contact: linux-input@vger.kernel.org
Description:
Writing to this file sets which one of the four (for Intuos 4)
or of the right four (for Cintiq 21UX2 and Cintiq 24HD) status
LEDs is active (0..3). The other three LEDs on the same side are
always inactive.
Writing to this file sets which one of the four (for Intuos 4
and Intuos 5) or of the right four (for Cintiq 21UX2 and Cintiq
24HD) status LEDs is active (0..3). The other three LEDs on the
same side are always inactive.
What: /sys/bus/usb/devices/<busnum>-<devnum>:<cfg>.<intf>/wacom_led/status_led1_select
Date: September 2011

View File

@ -0,0 +1,20 @@
* SPEAr keyboard controller
Required properties:
- compatible: "st,spear300-kbd"
Optional properties, in addition to those specified by the shared
matrix-keyboard bindings:
- autorepeat: bool: enables key autorepeat
- st,mode: keyboard mode: 0 - 9x9, 1 - 6x6, 2 - 2x2
Example:
kbd@fc400000 {
compatible = "st,spear300-kbd";
reg = <0xfc400000 0x100>;
linux,keymap = < 0x00030012
0x0102003a >;
autorepeat;
st,mode = <0>;
};

View File

@ -0,0 +1,16 @@
* NXP LPC32xx SoC Touchscreen Controller (TSC)
Required properties:
- compatible: must be "nxp,lpc3220-tsc"
- reg: physical base address of the controller and length of memory mapped
region.
- interrupts: The TSC/ADC interrupt
Example:
tsc@40048000 {
compatible = "nxp,lpc3220-tsc";
reg = <0x40048000 0x1000>;
interrupt-parent = <&mic>;
interrupts = <39 0>;
};

View File

@ -0,0 +1,37 @@
Vibra driver for the twl6040 family
The vibra driver is a child of the twl6040 MFD dirver.
Documentation/devicetree/bindings/mfd/twl6040.txt
Required properties:
- compatible : Must be "ti,twl6040-vibra";
- interrupts: 4, Vibra overcurrent interrupt
- vddvibl-supply: Regulator supplying the left vibra motor
- vddvibr-supply: Regulator supplying the right vibra motor
- vibldrv_res: Board specific left driver resistance
- vibrdrv_res: Board specific right driver resistance
- viblmotor_res: Board specific left motor resistance
- vibrmotor_res: Board specific right motor resistance
Optional properties:
- vddvibl_uV: If the vddvibl default voltage need to be changed
- vddvibr_uV: If the vddvibr default voltage need to be changed
Example:
/*
* 8-channel high quality low-power audio codec
* http://www.ti.com/lit/ds/symlink/twl6040.pdf
*/
twl6040: twl6040@4b {
...
twl6040_vibra: twl6040@1 {
compatible = "ti,twl6040-vibra";
interrupts = <4>;
vddvibl-supply = <&vbat>;
vddvibr-supply = <&vbat>;
vibldrv_res = <8>;
vibrdrv_res = <3>;
viblmotor_res = <10>;
vibrmotor_res = <10>;
};
};

View File

@ -3465,6 +3465,8 @@ Q: http://patchwork.kernel.org/project/linux-input/list/
T: git git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input.git
S: Maintained
F: drivers/input/
F: include/linux/input.h
F: include/linux/input/
INPUT MULTITOUCH (MT) PROTOCOL
M: Henrik Rydberg <rydberg@euromail.se>

View File

@ -25,10 +25,6 @@ config INPUT
if INPUT
config INPUT_OF_MATRIX_KEYMAP
depends on USE_OF
bool
config INPUT_FF_MEMLESS
tristate "Support for memoryless force-feedback devices"
help
@ -68,6 +64,19 @@ config INPUT_SPARSEKMAP
To compile this driver as a module, choose M here: the
module will be called sparse-keymap.
config INPUT_MATRIXKMAP
tristate "Matrix keymap support library"
help
Say Y here if you are using a driver for an input
device that uses matrix keymap. This option is only
useful for out-of-tree drivers since in-tree drivers
select it automatically.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called matrix-keymap.
comment "Userland interfaces"
config INPUT_MOUSEDEV

View File

@ -10,6 +10,7 @@ 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
obj-$(CONFIG_INPUT_SPARSEKMAP) += sparse-keymap.o
obj-$(CONFIG_INPUT_MATRIXKMAP) += matrix-keymap.o
obj-$(CONFIG_INPUT_MOUSEDEV) += mousedev.o
obj-$(CONFIG_INPUT_JOYDEV) += joydev.o
@ -24,4 +25,3 @@ obj-$(CONFIG_INPUT_TOUCHSCREEN) += touchscreen/
obj-$(CONFIG_INPUT_MISC) += misc/
obj-$(CONFIG_INPUT_APMPOWER) += apm-power.o
obj-$(CONFIG_INPUT_OF_MATRIX_KEYMAP) += of_keymap.o

View File

@ -180,7 +180,10 @@ static int evdev_grab(struct evdev *evdev, struct evdev_client *client)
static int evdev_ungrab(struct evdev *evdev, struct evdev_client *client)
{
if (evdev->grab != client)
struct evdev_client *grab = rcu_dereference_protected(evdev->grab,
lockdep_is_held(&evdev->mutex));
if (grab != client)
return -EINVAL;
rcu_assign_pointer(evdev->grab, NULL);
@ -259,8 +262,7 @@ static int evdev_release(struct inode *inode, struct file *file)
struct evdev *evdev = client->evdev;
mutex_lock(&evdev->mutex);
if (evdev->grab == client)
evdev_ungrab(evdev, client);
evdev_ungrab(evdev, client);
mutex_unlock(&evdev->mutex);
evdev_detach_client(evdev, client);
@ -343,7 +345,7 @@ static ssize_t evdev_write(struct file *file, const char __user *buffer,
struct input_event event;
int retval = 0;
if (count < input_event_size())
if (count != 0 && count < input_event_size())
return -EINVAL;
retval = mutex_lock_interruptible(&evdev->mutex);
@ -355,7 +357,8 @@ static ssize_t evdev_write(struct file *file, const char __user *buffer,
goto out;
}
do {
while (retval + input_event_size() <= count) {
if (input_event_from_user(buffer + retval, &event)) {
retval = -EFAULT;
goto out;
@ -364,7 +367,7 @@ static ssize_t evdev_write(struct file *file, const char __user *buffer,
input_inject_event(&evdev->handle,
event.type, event.code, event.value);
} while (retval + input_event_size() <= count);
}
out:
mutex_unlock(&evdev->mutex);
@ -395,35 +398,49 @@ static ssize_t evdev_read(struct file *file, char __user *buffer,
struct evdev_client *client = file->private_data;
struct evdev *evdev = client->evdev;
struct input_event event;
int retval = 0;
size_t read = 0;
int error;
if (count < input_event_size())
if (count != 0 && count < input_event_size())
return -EINVAL;
if (!(file->f_flags & O_NONBLOCK)) {
retval = wait_event_interruptible(evdev->wait,
client->packet_head != client->tail ||
!evdev->exist);
if (retval)
return retval;
for (;;) {
if (!evdev->exist)
return -ENODEV;
if (client->packet_head == client->tail &&
(file->f_flags & O_NONBLOCK))
return -EAGAIN;
/*
* count == 0 is special - no IO is done but we check
* for error conditions (see above).
*/
if (count == 0)
break;
while (read + input_event_size() <= count &&
evdev_fetch_next_event(client, &event)) {
if (input_event_to_user(buffer + read, &event))
return -EFAULT;
read += input_event_size();
}
if (read)
break;
if (!(file->f_flags & O_NONBLOCK)) {
error = wait_event_interruptible(evdev->wait,
client->packet_head != client->tail ||
!evdev->exist);
if (error)
return error;
}
}
if (!evdev->exist)
return -ENODEV;
while (retval + input_event_size() <= count &&
evdev_fetch_next_event(client, &event)) {
if (input_event_to_user(buffer + retval, &event))
return -EFAULT;
retval += input_event_size();
}
if (retval == 0 && (file->f_flags & O_NONBLOCK))
return -EAGAIN;
return retval;
return read;
}
/* No kernel lock - fine */

View File

@ -125,15 +125,4 @@ static struct pci_driver emu_driver = {
.remove = __devexit_p(emu_remove),
};
static int __init emu_init(void)
{
return pci_register_driver(&emu_driver);
}
static void __exit emu_exit(void)
{
pci_unregister_driver(&emu_driver);
}
module_init(emu_init);
module_exit(emu_exit);
module_pci_driver(emu_driver);

View File

@ -144,6 +144,7 @@ static const struct pci_device_id fm801_gp_id_table[] = {
{ PCI_VENDOR_ID_FORTEMEDIA, PCI_DEVICE_ID_FM801_GP, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
{ 0 }
};
MODULE_DEVICE_TABLE(pci, fm801_gp_id_table);
static struct pci_driver fm801_gp_driver = {
.name = "FM801_gameport",
@ -152,20 +153,7 @@ static struct pci_driver fm801_gp_driver = {
.remove = __devexit_p(fm801_gp_remove),
};
static int __init fm801_gp_init(void)
{
return pci_register_driver(&fm801_gp_driver);
}
static void __exit fm801_gp_exit(void)
{
pci_unregister_driver(&fm801_gp_driver);
}
module_init(fm801_gp_init);
module_exit(fm801_gp_exit);
MODULE_DEVICE_TABLE(pci, fm801_gp_id_table);
module_pci_driver(fm801_gp_driver);
MODULE_DESCRIPTION("FM801 gameport driver");
MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>");

View File

@ -413,15 +413,4 @@ static struct gameport_driver a3d_drv = {
.disconnect = a3d_disconnect,
};
static int __init a3d_init(void)
{
return gameport_register_driver(&a3d_drv);
}
static void __exit a3d_exit(void)
{
gameport_unregister_driver(&a3d_drv);
}
module_init(a3d_init);
module_exit(a3d_exit);
module_gameport_driver(a3d_drv);

View File

@ -557,10 +557,6 @@ static void adi_disconnect(struct gameport *gameport)
kfree(port);
}
/*
* The gameport device structure.
*/
static struct gameport_driver adi_drv = {
.driver = {
.name = "adi",
@ -570,15 +566,4 @@ static struct gameport_driver adi_drv = {
.disconnect = adi_disconnect,
};
static int __init adi_init(void)
{
return gameport_register_driver(&adi_drv);
}
static void __exit adi_exit(void)
{
gameport_unregister_driver(&adi_drv);
}
module_init(adi_init);
module_exit(adi_exit);
module_gameport_driver(adi_drv);

View File

@ -261,15 +261,4 @@ static struct gameport_driver cobra_drv = {
.disconnect = cobra_disconnect,
};
static int __init cobra_init(void)
{
return gameport_register_driver(&cobra_drv);
}
static void __exit cobra_exit(void)
{
gameport_unregister_driver(&cobra_drv);
}
module_init(cobra_init);
module_exit(cobra_exit);
module_gameport_driver(cobra_drv);

View File

@ -373,15 +373,4 @@ static struct gameport_driver gf2k_drv = {
.disconnect = gf2k_disconnect,
};
static int __init gf2k_init(void)
{
return gameport_register_driver(&gf2k_drv);
}
static void __exit gf2k_exit(void)
{
gameport_unregister_driver(&gf2k_drv);
}
module_init(gf2k_init);
module_exit(gf2k_exit);
module_gameport_driver(gf2k_drv);

View File

@ -424,15 +424,4 @@ static struct gameport_driver grip_drv = {
.disconnect = grip_disconnect,
};
static int __init grip_init(void)
{
return gameport_register_driver(&grip_drv);
}
static void __exit grip_exit(void)
{
gameport_unregister_driver(&grip_drv);
}
module_init(grip_init);
module_exit(grip_exit);
module_gameport_driver(grip_drv);

View File

@ -687,15 +687,4 @@ static struct gameport_driver grip_drv = {
.disconnect = grip_disconnect,
};
static int __init grip_init(void)
{
return gameport_register_driver(&grip_drv);
}
static void __exit grip_exit(void)
{
gameport_unregister_driver(&grip_drv);
}
module_init(grip_init);
module_exit(grip_exit);
module_gameport_driver(grip_drv);

View File

@ -281,15 +281,4 @@ static struct gameport_driver guillemot_drv = {
.disconnect = guillemot_disconnect,
};
static int __init guillemot_init(void)
{
return gameport_register_driver(&guillemot_drv);
}
static void __exit guillemot_exit(void)
{
gameport_unregister_driver(&guillemot_drv);
}
module_init(guillemot_init);
module_exit(guillemot_exit);
module_gameport_driver(guillemot_drv);

View File

@ -311,15 +311,4 @@ static struct gameport_driver interact_drv = {
.disconnect = interact_disconnect,
};
static int __init interact_init(void)
{
return gameport_register_driver(&interact_drv);
}
static void __exit interact_exit(void)
{
gameport_unregister_driver(&interact_drv);
}
module_init(interact_init);
module_exit(interact_exit);
module_gameport_driver(interact_drv);

View File

@ -159,15 +159,4 @@ static struct gameport_driver joydump_drv = {
.disconnect = joydump_disconnect,
};
static int __init joydump_init(void)
{
return gameport_register_driver(&joydump_drv);
}
static void __exit joydump_exit(void)
{
gameport_unregister_driver(&joydump_drv);
}
module_init(joydump_init);
module_exit(joydump_exit);
module_gameport_driver(joydump_drv);

View File

@ -222,19 +222,4 @@ static struct serio_driver magellan_drv = {
.disconnect = magellan_disconnect,
};
/*
* The functions for inserting/removing us as a module.
*/
static int __init magellan_init(void)
{
return serio_register_driver(&magellan_drv);
}
static void __exit magellan_exit(void)
{
serio_unregister_driver(&magellan_drv);
}
module_init(magellan_init);
module_exit(magellan_exit);
module_serio_driver(magellan_drv);

View File

@ -820,15 +820,4 @@ static struct gameport_driver sw_drv = {
.disconnect = sw_disconnect,
};
static int __init sw_init(void)
{
return gameport_register_driver(&sw_drv);
}
static void __exit sw_exit(void)
{
gameport_unregister_driver(&sw_drv);
}
module_init(sw_init);
module_exit(sw_exit);
module_gameport_driver(sw_drv);

View File

@ -296,19 +296,4 @@ static struct serio_driver spaceball_drv = {
.disconnect = spaceball_disconnect,
};
/*
* The functions for inserting/removing us as a module.
*/
static int __init spaceball_init(void)
{
return serio_register_driver(&spaceball_drv);
}
static void __exit spaceball_exit(void)
{
serio_unregister_driver(&spaceball_drv);
}
module_init(spaceball_init);
module_exit(spaceball_exit);
module_serio_driver(spaceball_drv);

View File

@ -237,19 +237,4 @@ static struct serio_driver spaceorb_drv = {
.disconnect = spaceorb_disconnect,
};
/*
* The functions for inserting/removing us as a module.
*/
static int __init spaceorb_init(void)
{
return serio_register_driver(&spaceorb_drv);
}
static void __exit spaceorb_exit(void)
{
serio_unregister_driver(&spaceorb_drv);
}
module_init(spaceorb_init);
module_exit(spaceorb_exit);
module_serio_driver(spaceorb_drv);

View File

@ -208,19 +208,4 @@ static struct serio_driver stinger_drv = {
.disconnect = stinger_disconnect,
};
/*
* The functions for inserting/removing us as a module.
*/
static int __init stinger_init(void)
{
return serio_register_driver(&stinger_drv);
}
static void __exit stinger_exit(void)
{
serio_unregister_driver(&stinger_drv);
}
module_init(stinger_init);
module_exit(stinger_exit);
module_serio_driver(stinger_drv);

View File

@ -436,15 +436,4 @@ static struct gameport_driver tmdc_drv = {
.disconnect = tmdc_disconnect,
};
static int __init tmdc_init(void)
{
return gameport_register_driver(&tmdc_drv);
}
static void __exit tmdc_exit(void)
{
gameport_unregister_driver(&tmdc_drv);
}
module_init(tmdc_init);
module_exit(tmdc_exit);
module_gameport_driver(tmdc_drv);

View File

@ -257,19 +257,4 @@ static struct serio_driver twidjoy_drv = {
.disconnect = twidjoy_disconnect,
};
/*
* The functions for inserting/removing us as a module.
*/
static int __init twidjoy_init(void)
{
return serio_register_driver(&twidjoy_drv);
}
static void __exit twidjoy_exit(void)
{
serio_unregister_driver(&twidjoy_drv);
}
module_init(twidjoy_init);
module_exit(twidjoy_exit);
module_serio_driver(twidjoy_drv);

View File

@ -217,19 +217,4 @@ static struct serio_driver warrior_drv = {
.disconnect = warrior_disconnect,
};
/*
* The functions for inserting/removing us as a module.
*/
static int __init warrior_init(void)
{
return serio_register_driver(&warrior_drv);
}
static void __exit warrior_exit(void)
{
serio_unregister_driver(&warrior_drv);
}
module_init(warrior_init);
module_exit(warrior_exit);
module_serio_driver(warrior_drv);

View File

@ -225,19 +225,4 @@ static struct serio_driver zhenhua_drv = {
.disconnect = zhenhua_disconnect,
};
/*
* The functions for inserting/removing us as a module.
*/
static int __init zhenhua_init(void)
{
return serio_register_driver(&zhenhua_drv);
}
static void __exit zhenhua_exit(void)
{
serio_unregister_driver(&zhenhua_drv);
}
module_init(zhenhua_init);
module_exit(zhenhua_exit);
module_serio_driver(zhenhua_drv);

View File

@ -166,6 +166,7 @@ config KEYBOARD_LKKBD
config KEYBOARD_EP93XX
tristate "EP93xx Matrix Keypad support"
depends on ARCH_EP93XX
select INPUT_MATRIXKMAP
help
Say Y here to enable the matrix keypad on the Cirrus EP93XX.
@ -224,6 +225,7 @@ config KEYBOARD_TCA6416
config KEYBOARD_TCA8418
tristate "TCA8418 Keypad Support"
depends on I2C
select INPUT_MATRIXKMAP
help
This driver implements basic keypad functionality
for keys connected through TCA8418 keypad decoder.
@ -240,6 +242,7 @@ config KEYBOARD_TCA8418
config KEYBOARD_MATRIX
tristate "GPIO driven matrix keypad support"
depends on GENERIC_GPIO
select INPUT_MATRIXKMAP
help
Enable support for GPIO driven matrix keypad.
@ -309,6 +312,17 @@ config KEYBOARD_LM8323
To compile this driver as a module, choose M here: the
module will be called lm8323.
config KEYBOARD_LM8333
tristate "LM8333 keypad chip"
depends on I2C
select INPUT_MATRIXKMAP
help
If you say yes here you get support for the National Semiconductor
LM8333 keypad controller.
To compile this driver as a module, choose M here: the
module will be called lm8333.
config KEYBOARD_LOCOMO
tristate "LoCoMo Keyboard Support"
depends on SHARP_LOCOMO
@ -366,6 +380,7 @@ config KEYBOARD_MPR121
config KEYBOARD_IMX
tristate "IMX keypad support"
depends on ARCH_MXC
select INPUT_MATRIXKMAP
help
Enable support for IMX keypad port.
@ -384,6 +399,7 @@ config KEYBOARD_NEWTON
config KEYBOARD_NOMADIK
tristate "ST-Ericsson Nomadik SKE keyboard"
depends on PLAT_NOMADIK
select INPUT_MATRIXKMAP
help
Say Y here if you want to use a keypad provided on the SKE controller
used on the Ux500 and Nomadik platforms
@ -394,7 +410,7 @@ config KEYBOARD_NOMADIK
config KEYBOARD_TEGRA
tristate "NVIDIA Tegra internal matrix keyboard controller support"
depends on ARCH_TEGRA
select INPUT_OF_MATRIX_KEYMAP if USE_OF
select INPUT_MATRIXKMAP
help
Say Y here if you want to use a matrix keyboard connected directly
to the internal keyboard controller on Tegra SoCs.
@ -432,6 +448,7 @@ config KEYBOARD_PXA930_ROTARY
config KEYBOARD_PMIC8XXX
tristate "Qualcomm PMIC8XXX keypad support"
depends on MFD_PM8XXX
select INPUT_MATRIXKMAP
help
Say Y here if you want to enable the driver for the PMIC8XXX
keypad provided as a reference design from Qualcomm. This is intended
@ -443,6 +460,7 @@ config KEYBOARD_PMIC8XXX
config KEYBOARD_SAMSUNG
tristate "Samsung keypad support"
depends on HAVE_CLK
select INPUT_MATRIXKMAP
help
Say Y here if you want to use the keypad on your Samsung mobile
device.
@ -485,6 +503,7 @@ config KEYBOARD_SH_KEYSC
config KEYBOARD_STMPE
tristate "STMPE keypad support"
depends on MFD_STMPE
select INPUT_MATRIXKMAP
help
Say Y here if you want to use the keypad controller on STMPE I/O
expanders.
@ -505,6 +524,7 @@ config KEYBOARD_DAVINCI
config KEYBOARD_OMAP
tristate "TI OMAP keypad support"
depends on (ARCH_OMAP1 || ARCH_OMAP2)
select INPUT_MATRIXKMAP
help
Say Y here if you want to use the OMAP keypad.
@ -512,9 +532,10 @@ config KEYBOARD_OMAP
module will be called omap-keypad.
config KEYBOARD_OMAP4
tristate "TI OMAP4 keypad support"
tristate "TI OMAP4+ keypad support"
select INPUT_MATRIXKMAP
help
Say Y here if you want to use the OMAP4 keypad.
Say Y here if you want to use the OMAP4+ keypad.
To compile this driver as a module, choose M here: the
module will be called omap4-keypad.
@ -522,6 +543,7 @@ config KEYBOARD_OMAP4
config KEYBOARD_SPEAR
tristate "ST SPEAR keyboard support"
depends on PLAT_SPEAR
select INPUT_MATRIXKMAP
help
Say Y here if you want to use the SPEAR keyboard.
@ -531,6 +553,7 @@ config KEYBOARD_SPEAR
config KEYBOARD_TC3589X
tristate "TC3589X Keypad support"
depends on MFD_TC3589X
select INPUT_MATRIXKMAP
help
Say Y here if you want to use the keypad controller on
TC35892/3 I/O expander.
@ -541,6 +564,7 @@ config KEYBOARD_TC3589X
config KEYBOARD_TNETV107X
tristate "TI TNETV107X keypad support"
depends on ARCH_DAVINCI_TNETV107X
select INPUT_MATRIXKMAP
help
Say Y here if you want to use the TNETV107X keypad.
@ -550,6 +574,7 @@ config KEYBOARD_TNETV107X
config KEYBOARD_TWL4030
tristate "TI TWL4030/TWL5030/TPS659x0 keypad support"
depends on TWL4030_CORE
select INPUT_MATRIXKMAP
help
Say Y here if your board use the keypad controller on
TWL4030 family chips. It's safe to say enable this
@ -573,6 +598,7 @@ config KEYBOARD_XTKBD
config KEYBOARD_W90P910
tristate "W90P910 Matrix Keypad support"
depends on ARCH_W90X900
select INPUT_MATRIXKMAP
help
Say Y here to enable the matrix keypad on evaluation board
based on W90P910.

View File

@ -24,6 +24,7 @@ obj-$(CONFIG_KEYBOARD_HP6XX) += jornada680_kbd.o
obj-$(CONFIG_KEYBOARD_HP7XX) += jornada720_kbd.o
obj-$(CONFIG_KEYBOARD_LKKBD) += lkkbd.o
obj-$(CONFIG_KEYBOARD_LM8323) += lm8323.o
obj-$(CONFIG_KEYBOARD_LM8333) += lm8333.o
obj-$(CONFIG_KEYBOARD_LOCOMO) += locomokbd.o
obj-$(CONFIG_KEYBOARD_MAPLE) += maple_keyb.o
obj-$(CONFIG_KEYBOARD_MATRIX) += matrix_keypad.o

View File

@ -197,6 +197,7 @@ static int __devinit adp5588_gpio_add(struct adp5588_kpad *kpad)
kpad->gc.base = gpio_data->gpio_start;
kpad->gc.label = kpad->client->name;
kpad->gc.owner = THIS_MODULE;
kpad->gc.names = gpio_data->names;
mutex_init(&kpad->gpio_lock);

View File

@ -433,7 +433,7 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
if (printk_ratelimit())
dev_warn(&serio->dev,
"Spurious %s on %s. "
"Some program might be trying access hardware directly.\n",
"Some program might be trying to access hardware directly.\n",
data == ATKBD_RET_ACK ? "ACK" : "NAK", serio->phys);
goto out;
case ATKBD_RET_ERR:

View File

@ -182,16 +182,10 @@ static void ep93xx_keypad_close(struct input_dev *pdev)
}
#ifdef CONFIG_PM
/*
* NOTE: I don't know if this is correct, or will work on the ep93xx.
*
* None of the existing ep93xx drivers have power management support.
* But, this is basically what the pxa27x_keypad driver does.
*/
static int ep93xx_keypad_suspend(struct platform_device *pdev,
pm_message_t state)
#ifdef CONFIG_PM_SLEEP
static int ep93xx_keypad_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct ep93xx_keypad *keypad = platform_get_drvdata(pdev);
struct input_dev *input_dev = keypad->input_dev;
@ -210,8 +204,9 @@ static int ep93xx_keypad_suspend(struct platform_device *pdev,
return 0;
}
static int ep93xx_keypad_resume(struct platform_device *pdev)
static int ep93xx_keypad_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct ep93xx_keypad *keypad = platform_get_drvdata(pdev);
struct input_dev *input_dev = keypad->input_dev;
@ -232,10 +227,10 @@ static int ep93xx_keypad_resume(struct platform_device *pdev)
return 0;
}
#else /* !CONFIG_PM */
#define ep93xx_keypad_suspend NULL
#define ep93xx_keypad_resume NULL
#endif /* !CONFIG_PM */
#endif
static SIMPLE_DEV_PM_OPS(ep93xx_keypad_pm_ops,
ep93xx_keypad_suspend, ep93xx_keypad_resume);
static int __devinit ep93xx_keypad_probe(struct platform_device *pdev)
{
@ -308,19 +303,16 @@ static int __devinit ep93xx_keypad_probe(struct platform_device *pdev)
input_dev->open = ep93xx_keypad_open;
input_dev->close = ep93xx_keypad_close;
input_dev->dev.parent = &pdev->dev;
input_dev->keycode = keypad->keycodes;
input_dev->keycodesize = sizeof(keypad->keycodes[0]);
input_dev->keycodemax = ARRAY_SIZE(keypad->keycodes);
input_set_drvdata(input_dev, keypad);
err = matrix_keypad_build_keymap(keymap_data, NULL,
EP93XX_MATRIX_ROWS, EP93XX_MATRIX_COLS,
keypad->keycodes, input_dev);
if (err)
goto failed_free_dev;
input_dev->evbit[0] = BIT_MASK(EV_KEY);
if (keypad->pdata->flags & EP93XX_KEYPAD_AUTOREPEAT)
input_dev->evbit[0] |= BIT_MASK(EV_REP);
matrix_keypad_build_keymap(keymap_data, 3,
input_dev->keycode, input_dev->keybit);
platform_set_drvdata(pdev, keypad);
__set_bit(EV_REP, input_dev->evbit);
input_set_drvdata(input_dev, keypad);
err = request_irq(keypad->irq, ep93xx_keypad_irq_handler,
0, pdev->name, keypad);
@ -331,6 +323,7 @@ static int __devinit ep93xx_keypad_probe(struct platform_device *pdev)
if (err)
goto failed_free_irq;
platform_set_drvdata(pdev, keypad);
device_init_wakeup(&pdev->dev, 1);
return 0;
@ -384,11 +377,10 @@ static struct platform_driver ep93xx_keypad_driver = {
.driver = {
.name = "ep93xx-keypad",
.owner = THIS_MODULE,
.pm = &ep93xx_keypad_pm_ops,
},
.probe = ep93xx_keypad_probe,
.remove = __devexit_p(ep93xx_keypad_remove),
.suspend = ep93xx_keypad_suspend,
.resume = ep93xx_keypad_resume,
};
module_platform_driver(ep93xx_keypad_driver);

View File

@ -583,15 +583,4 @@ static struct serio_driver hil_serio_drv = {
.interrupt = hil_dev_interrupt
};
static int __init hil_dev_init(void)
{
return serio_register_driver(&hil_serio_drv);
}
static void __exit hil_dev_exit(void)
{
serio_unregister_driver(&hil_serio_drv);
}
module_init(hil_dev_init);
module_exit(hil_dev_exit);
module_serio_driver(hil_serio_drv);

View File

@ -481,7 +481,7 @@ static int __devinit imx_keypad_probe(struct platform_device *pdev)
}
if (keypad->rows_en_mask > ((1 << MAX_MATRIX_KEY_ROWS) - 1) ||
keypad->cols_en_mask > ((1 << MAX_MATRIX_KEY_COLS) - 1)) {
keypad->cols_en_mask > ((1 << MAX_MATRIX_KEY_COLS) - 1)) {
dev_err(&pdev->dev,
"invalid key data (too many rows or colums)\n");
error = -EINVAL;
@ -496,14 +496,17 @@ static int __devinit imx_keypad_probe(struct platform_device *pdev)
input_dev->dev.parent = &pdev->dev;
input_dev->open = imx_keypad_open;
input_dev->close = imx_keypad_close;
input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
input_dev->keycode = keypad->keycodes;
input_dev->keycodesize = sizeof(keypad->keycodes[0]);
input_dev->keycodemax = ARRAY_SIZE(keypad->keycodes);
matrix_keypad_build_keymap(keymap_data, MATRIX_ROW_SHIFT,
keypad->keycodes, input_dev->keybit);
error = matrix_keypad_build_keymap(keymap_data, NULL,
MAX_MATRIX_KEY_ROWS,
MAX_MATRIX_KEY_COLS,
keypad->keycodes, input_dev);
if (error) {
dev_err(&pdev->dev, "failed to build keymap\n");
goto failed_clock_put;
}
__set_bit(EV_REP, input_dev->evbit);
input_set_capability(input_dev, EV_MSC, MSC_SCAN);
input_set_drvdata(input_dev, keypad);

View File

@ -731,19 +731,4 @@ static struct serio_driver lkkbd_drv = {
.interrupt = lkkbd_interrupt,
};
/*
* The functions for insering/removing us as a module.
*/
static int __init lkkbd_init(void)
{
return serio_register_driver(&lkkbd_drv);
}
static void __exit lkkbd_exit(void)
{
serio_unregister_driver(&lkkbd_drv);
}
module_init(lkkbd_init);
module_exit(lkkbd_exit);
module_serio_driver(lkkbd_drv);

View File

@ -0,0 +1,235 @@
/*
* LM8333 keypad driver
* Copyright (C) 2012 Wolfram Sang, Pengutronix <w.sang@pengutronix.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License.
*/
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/irq.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/input/matrix_keypad.h>
#include <linux/input/lm8333.h>
#define LM8333_FIFO_READ 0x20
#define LM8333_DEBOUNCE 0x22
#define LM8333_READ_INT 0xD0
#define LM8333_ACTIVE 0xE4
#define LM8333_READ_ERROR 0xF0
#define LM8333_KEYPAD_IRQ (1 << 0)
#define LM8333_ERROR_IRQ (1 << 3)
#define LM8333_ERROR_KEYOVR 0x04
#define LM8333_ERROR_FIFOOVR 0x40
#define LM8333_FIFO_TRANSFER_SIZE 16
#define LM8333_NUM_ROWS 8
#define LM8333_NUM_COLS 16
#define LM8333_ROW_SHIFT 4
struct lm8333 {
struct i2c_client *client;
struct input_dev *input;
unsigned short keycodes[LM8333_NUM_ROWS << LM8333_ROW_SHIFT];
};
/* The accessors try twice because the first access may be needed for wakeup */
#define LM8333_READ_RETRIES 2
int lm8333_read8(struct lm8333 *lm8333, u8 cmd)
{
int retries = 0, ret;
do {
ret = i2c_smbus_read_byte_data(lm8333->client, cmd);
} while (ret < 0 && retries++ < LM8333_READ_RETRIES);
return ret;
}
int lm8333_write8(struct lm8333 *lm8333, u8 cmd, u8 val)
{
int retries = 0, ret;
do {
ret = i2c_smbus_write_byte_data(lm8333->client, cmd, val);
} while (ret < 0 && retries++ < LM8333_READ_RETRIES);
return ret;
}
int lm8333_read_block(struct lm8333 *lm8333, u8 cmd, u8 len, u8 *buf)
{
int retries = 0, ret;
do {
ret = i2c_smbus_read_i2c_block_data(lm8333->client,
cmd, len, buf);
} while (ret < 0 && retries++ < LM8333_READ_RETRIES);
return ret;
}
static void lm8333_key_handler(struct lm8333 *lm8333)
{
struct input_dev *input = lm8333->input;
u8 keys[LM8333_FIFO_TRANSFER_SIZE];
u8 code, pressed;
int i, ret;
ret = lm8333_read_block(lm8333, LM8333_FIFO_READ,
LM8333_FIFO_TRANSFER_SIZE, keys);
if (ret != LM8333_FIFO_TRANSFER_SIZE) {
dev_err(&lm8333->client->dev,
"Error %d while reading FIFO\n", ret);
return;
}
for (i = 0; keys[i] && i < LM8333_FIFO_TRANSFER_SIZE; i++) {
pressed = keys[i] & 0x80;
code = keys[i] & 0x7f;
input_event(input, EV_MSC, MSC_SCAN, code);
input_report_key(input, lm8333->keycodes[code], pressed);
}
input_sync(input);
}
static irqreturn_t lm8333_irq_thread(int irq, void *data)
{
struct lm8333 *lm8333 = data;
u8 status = lm8333_read8(lm8333, LM8333_READ_INT);
if (!status)
return IRQ_NONE;
if (status & LM8333_ERROR_IRQ) {
u8 err = lm8333_read8(lm8333, LM8333_READ_ERROR);
if (err & (LM8333_ERROR_KEYOVR | LM8333_ERROR_FIFOOVR)) {
u8 dummy[LM8333_FIFO_TRANSFER_SIZE];
lm8333_read_block(lm8333, LM8333_FIFO_READ,
LM8333_FIFO_TRANSFER_SIZE, dummy);
}
dev_err(&lm8333->client->dev, "Got error %02x\n", err);
}
if (status & LM8333_KEYPAD_IRQ)
lm8333_key_handler(lm8333);
return IRQ_HANDLED;
}
static int __devinit lm8333_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
const struct lm8333_platform_data *pdata = client->dev.platform_data;
struct lm8333 *lm8333;
struct input_dev *input;
int err, active_time;
if (!pdata)
return -EINVAL;
active_time = pdata->active_time ?: 500;
if (active_time / 3 <= pdata->debounce_time / 3) {
dev_err(&client->dev, "Active time not big enough!\n");
return -EINVAL;
}
lm8333 = kzalloc(sizeof(*lm8333), GFP_KERNEL);
input = input_allocate_device();
if (!lm8333 || !input) {
err = -ENOMEM;
goto free_mem;
}
lm8333->client = client;
lm8333->input = input;
input->name = client->name;
input->dev.parent = &client->dev;
input->id.bustype = BUS_I2C;
input_set_capability(input, EV_MSC, MSC_SCAN);
err = matrix_keypad_build_keymap(pdata->matrix_data, NULL,
LM8333_NUM_ROWS, LM8333_NUM_COLS,
lm8333->keycodes, input);
if (err)
goto free_mem;
if (pdata->debounce_time) {
err = lm8333_write8(lm8333, LM8333_DEBOUNCE,
pdata->debounce_time / 3);
if (err)
dev_warn(&client->dev, "Unable to set debounce time\n");
}
if (pdata->active_time) {
err = lm8333_write8(lm8333, LM8333_ACTIVE,
pdata->active_time / 3);
if (err)
dev_warn(&client->dev, "Unable to set active time\n");
}
err = request_threaded_irq(client->irq, NULL, lm8333_irq_thread,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
"lm8333", lm8333);
if (err)
goto free_mem;
err = input_register_device(input);
if (err)
goto free_irq;
i2c_set_clientdata(client, lm8333);
return 0;
free_irq:
free_irq(client->irq, lm8333);
free_mem:
input_free_device(input);
kfree(lm8333);
return err;
}
static int __devexit lm8333_remove(struct i2c_client *client)
{
struct lm8333 *lm8333 = i2c_get_clientdata(client);
free_irq(client->irq, lm8333);
input_unregister_device(lm8333->input);
kfree(lm8333);
return 0;
}
static const struct i2c_device_id lm8333_id[] = {
{ "lm8333", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, lm8333_id);
static struct i2c_driver lm8333_driver = {
.driver = {
.name = "lm8333",
.owner = THIS_MODULE,
},
.probe = lm8333_probe,
.remove = __devexit_p(lm8333_remove),
.id_table = lm8333_id,
};
module_i2c_driver(lm8333_driver);
MODULE_AUTHOR("Wolfram Sang <w.sang@pengutronix.de>");
MODULE_DESCRIPTION("LM8333 keyboard driver");
MODULE_LICENSE("GPL v2");

View File

@ -27,7 +27,6 @@
struct matrix_keypad {
const struct matrix_keypad_platform_data *pdata;
struct input_dev *input_dev;
unsigned short *keycodes;
unsigned int row_shift;
DECLARE_BITMAP(disabled_gpios, MATRIX_MAX_ROWS);
@ -38,6 +37,8 @@ struct matrix_keypad {
bool scan_pending;
bool stopped;
bool gpio_all_disabled;
unsigned short keycodes[];
};
/*
@ -224,7 +225,7 @@ static void matrix_keypad_stop(struct input_dev *dev)
disable_row_irqs(keypad);
}
#ifdef CONFIG_PM
#ifdef CONFIG_PM_SLEEP
static void matrix_keypad_enable_wakeup(struct matrix_keypad *keypad)
{
const struct matrix_keypad_platform_data *pdata = keypad->pdata;
@ -293,16 +294,16 @@ static int matrix_keypad_resume(struct device *dev)
return 0;
}
static const SIMPLE_DEV_PM_OPS(matrix_keypad_pm_ops,
matrix_keypad_suspend, matrix_keypad_resume);
#endif
static int __devinit init_matrix_gpio(struct platform_device *pdev,
struct matrix_keypad *keypad)
static SIMPLE_DEV_PM_OPS(matrix_keypad_pm_ops,
matrix_keypad_suspend, matrix_keypad_resume);
static int __devinit matrix_keypad_init_gpio(struct platform_device *pdev,
struct matrix_keypad *keypad)
{
const struct matrix_keypad_platform_data *pdata = keypad->pdata;
int i, err = -EINVAL;
int i, err;
/* initialized strobe lines as outputs, activated */
for (i = 0; i < pdata->num_col_gpios; i++) {
@ -348,8 +349,7 @@ static int __devinit init_matrix_gpio(struct platform_device *pdev,
"matrix-keypad", keypad);
if (err) {
dev_err(&pdev->dev,
"Unable to acquire interrupt "
"for GPIO line %i\n",
"Unable to acquire interrupt for GPIO line %i\n",
pdata->row_gpios[i]);
goto err_free_irqs;
}
@ -375,14 +375,33 @@ err_free_cols:
return err;
}
static void matrix_keypad_free_gpio(struct matrix_keypad *keypad)
{
const struct matrix_keypad_platform_data *pdata = keypad->pdata;
int i;
if (pdata->clustered_irq > 0) {
free_irq(pdata->clustered_irq, keypad);
} else {
for (i = 0; i < pdata->num_row_gpios; i++)
free_irq(gpio_to_irq(pdata->row_gpios[i]), keypad);
}
for (i = 0; i < pdata->num_row_gpios; i++)
gpio_free(pdata->row_gpios[i]);
for (i = 0; i < pdata->num_col_gpios; i++)
gpio_free(pdata->col_gpios[i]);
}
static int __devinit matrix_keypad_probe(struct platform_device *pdev)
{
const struct matrix_keypad_platform_data *pdata;
const struct matrix_keymap_data *keymap_data;
struct matrix_keypad *keypad;
struct input_dev *input_dev;
unsigned short *keycodes;
unsigned int row_shift;
size_t keymap_size;
int err;
pdata = pdev->dev.platform_data;
@ -398,20 +417,18 @@ static int __devinit matrix_keypad_probe(struct platform_device *pdev)
}
row_shift = get_count_order(pdata->num_col_gpios);
keypad = kzalloc(sizeof(struct matrix_keypad), GFP_KERNEL);
keycodes = kzalloc((pdata->num_row_gpios << row_shift) *
sizeof(*keycodes),
GFP_KERNEL);
keymap_size = (pdata->num_row_gpios << row_shift) *
sizeof(keypad->keycodes[0]);
keypad = kzalloc(sizeof(struct matrix_keypad) + keymap_size,
GFP_KERNEL);
input_dev = input_allocate_device();
if (!keypad || !keycodes || !input_dev) {
if (!keypad || !input_dev) {
err = -ENOMEM;
goto err_free_mem;
}
keypad->input_dev = input_dev;
keypad->pdata = pdata;
keypad->keycodes = keycodes;
keypad->row_shift = row_shift;
keypad->stopped = true;
INIT_DELAYED_WORK(&keypad->work, matrix_keypad_scan);
@ -420,38 +437,38 @@ static int __devinit matrix_keypad_probe(struct platform_device *pdev)
input_dev->name = pdev->name;
input_dev->id.bustype = BUS_HOST;
input_dev->dev.parent = &pdev->dev;
input_dev->evbit[0] = BIT_MASK(EV_KEY);
if (!pdata->no_autorepeat)
input_dev->evbit[0] |= BIT_MASK(EV_REP);
input_dev->open = matrix_keypad_start;
input_dev->close = matrix_keypad_stop;
input_dev->keycode = keycodes;
input_dev->keycodesize = sizeof(*keycodes);
input_dev->keycodemax = pdata->num_row_gpios << row_shift;
matrix_keypad_build_keymap(keymap_data, row_shift,
input_dev->keycode, input_dev->keybit);
err = matrix_keypad_build_keymap(keymap_data, NULL,
pdata->num_row_gpios,
pdata->num_col_gpios,
keypad->keycodes, input_dev);
if (err)
goto err_free_mem;
if (!pdata->no_autorepeat)
__set_bit(EV_REP, input_dev->evbit);
input_set_capability(input_dev, EV_MSC, MSC_SCAN);
input_set_drvdata(input_dev, keypad);
err = init_matrix_gpio(pdev, keypad);
err = matrix_keypad_init_gpio(pdev, keypad);
if (err)
goto err_free_mem;
err = input_register_device(keypad->input_dev);
if (err)
goto err_free_mem;
goto err_free_gpio;
device_init_wakeup(&pdev->dev, pdata->wakeup);
platform_set_drvdata(pdev, keypad);
return 0;
err_free_gpio:
matrix_keypad_free_gpio(keypad);
err_free_mem:
input_free_device(input_dev);
kfree(keycodes);
kfree(keypad);
return err;
}
@ -459,29 +476,15 @@ err_free_mem:
static int __devexit matrix_keypad_remove(struct platform_device *pdev)
{
struct matrix_keypad *keypad = platform_get_drvdata(pdev);
const struct matrix_keypad_platform_data *pdata = keypad->pdata;
int i;
device_init_wakeup(&pdev->dev, 0);
if (pdata->clustered_irq > 0) {
free_irq(pdata->clustered_irq, keypad);
} else {
for (i = 0; i < pdata->num_row_gpios; i++)
free_irq(gpio_to_irq(pdata->row_gpios[i]), keypad);
}
for (i = 0; i < pdata->num_row_gpios; i++)
gpio_free(pdata->row_gpios[i]);
for (i = 0; i < pdata->num_col_gpios; i++)
gpio_free(pdata->col_gpios[i]);
matrix_keypad_free_gpio(keypad);
input_unregister_device(keypad->input_dev);
platform_set_drvdata(pdev, NULL);
kfree(keypad->keycodes);
kfree(keypad);
platform_set_drvdata(pdev, NULL);
return 0;
}
@ -491,9 +494,7 @@ static struct platform_driver matrix_keypad_driver = {
.driver = {
.name = "matrix-keypad",
.owner = THIS_MODULE,
#ifdef CONFIG_PM
.pm = &matrix_keypad_pm_ops,
#endif
},
};
module_platform_driver(matrix_keypad_driver);

View File

@ -166,15 +166,4 @@ static struct serio_driver nkbd_drv = {
.disconnect = nkbd_disconnect,
};
static int __init nkbd_init(void)
{
return serio_register_driver(&nkbd_drv);
}
static void __exit nkbd_exit(void)
{
serio_unregister_driver(&nkbd_drv);
}
module_init(nkbd_init);
module_exit(nkbd_exit);
module_serio_driver(nkbd_drv);

View File

@ -39,7 +39,8 @@
#define SKE_KPRISA (0x1 << 2)
#define SKE_KEYPAD_ROW_SHIFT 3
#define SKE_KPD_KEYMAP_SIZE (8 * 8)
#define SKE_KPD_NUM_ROWS 8
#define SKE_KPD_NUM_COLS 8
/* keypad auto scan registers */
#define SKE_ASR0 0x20
@ -63,7 +64,7 @@ struct ske_keypad {
void __iomem *reg_base;
struct input_dev *input;
const struct ske_keypad_platform_data *board;
unsigned short keymap[SKE_KPD_KEYMAP_SIZE];
unsigned short keymap[SKE_KPD_NUM_ROWS * SKE_KPD_NUM_COLS];
struct clk *clk;
spinlock_t ske_keypad_lock;
};
@ -261,19 +262,18 @@ static int __init ske_keypad_probe(struct platform_device *pdev)
input->name = "ux500-ske-keypad";
input->dev.parent = &pdev->dev;
input->keycode = keypad->keymap;
input->keycodesize = sizeof(keypad->keymap[0]);
input->keycodemax = ARRAY_SIZE(keypad->keymap);
error = matrix_keypad_build_keymap(plat->keymap_data, NULL,
SKE_KPD_NUM_ROWS, SKE_KPD_NUM_COLS,
keypad->keymap, input);
if (error) {
dev_err(&pdev->dev, "Failed to build keymap\n");
goto err_iounmap;
}
input_set_capability(input, EV_MSC, MSC_SCAN);
__set_bit(EV_KEY, input->evbit);
if (!plat->no_autorepeat)
__set_bit(EV_REP, input->evbit);
matrix_keypad_build_keymap(plat->keymap_data, SKE_KEYPAD_ROW_SHIFT,
input->keycode, input->keybit);
clk_enable(keypad->clk);
/* go through board initialization helpers */

View File

@ -61,6 +61,7 @@ struct omap_kp {
unsigned int cols;
unsigned long delay;
unsigned int debounce;
unsigned short keymap[];
};
static DECLARE_TASKLET_DISABLED(kp_tasklet, omap_kp_tasklet, 0);
@ -316,13 +317,6 @@ static int __devinit omap_kp_probe(struct platform_device *pdev)
if (!cpu_is_omap24xx())
omap_writew(1, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
input_dev->keycode = &omap_kp[1];
input_dev->keycodesize = sizeof(unsigned short);
input_dev->keycodemax = keycodemax;
if (pdata->rep)
__set_bit(EV_REP, input_dev->evbit);
if (pdata->delay)
omap_kp->delay = pdata->delay;
@ -371,9 +365,6 @@ static int __devinit omap_kp_probe(struct platform_device *pdev)
goto err2;
/* setup input device */
__set_bit(EV_KEY, input_dev->evbit);
matrix_keypad_build_keymap(pdata->keymap_data, row_shift,
input_dev->keycode, input_dev->keybit);
input_dev->name = "omap-keypad";
input_dev->phys = "omap-keypad/input0";
input_dev->dev.parent = &pdev->dev;
@ -383,6 +374,15 @@ static int __devinit omap_kp_probe(struct platform_device *pdev)
input_dev->id.product = 0x0001;
input_dev->id.version = 0x0100;
if (pdata->rep)
__set_bit(EV_REP, input_dev->evbit);
ret = matrix_keypad_build_keymap(pdata->keymap_data, NULL,
pdata->rows, pdata->cols,
omap_kp->keymap, input_dev);
if (ret < 0)
goto err3;
ret = input_register_device(omap_kp->input);
if (ret < 0) {
printk(KERN_ERR "Unable to register omap-keypad input device\n");

View File

@ -68,19 +68,52 @@
#define OMAP4_MASK_IRQSTATUSDISABLE 0xFFFF
enum {
KBD_REVISION_OMAP4 = 0,
KBD_REVISION_OMAP5,
};
struct omap4_keypad {
struct input_dev *input;
void __iomem *base;
int irq;
unsigned int irq;
unsigned int rows;
unsigned int cols;
u32 reg_offset;
u32 irqreg_offset;
unsigned int row_shift;
unsigned char key_state[8];
unsigned short keymap[];
};
static int kbd_readl(struct omap4_keypad *keypad_data, u32 offset)
{
return __raw_readl(keypad_data->base +
keypad_data->reg_offset + offset);
}
static void kbd_writel(struct omap4_keypad *keypad_data, u32 offset, u32 value)
{
__raw_writel(value,
keypad_data->base + keypad_data->reg_offset + offset);
}
static int kbd_read_irqreg(struct omap4_keypad *keypad_data, u32 offset)
{
return __raw_readl(keypad_data->base +
keypad_data->irqreg_offset + offset);
}
static void kbd_write_irqreg(struct omap4_keypad *keypad_data,
u32 offset, u32 value)
{
__raw_writel(value,
keypad_data->base + keypad_data->irqreg_offset + offset);
}
/* Interrupt handler */
static irqreturn_t omap4_keypad_interrupt(int irq, void *dev_id)
{
@ -91,12 +124,11 @@ static irqreturn_t omap4_keypad_interrupt(int irq, void *dev_id)
u32 *new_state = (u32 *) key_state;
/* Disable interrupts */
__raw_writel(OMAP4_VAL_IRQDISABLE,
keypad_data->base + OMAP4_KBD_IRQENABLE);
kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQENABLE,
OMAP4_VAL_IRQDISABLE);
*new_state = __raw_readl(keypad_data->base + OMAP4_KBD_FULLCODE31_0);
*(new_state + 1) = __raw_readl(keypad_data->base
+ OMAP4_KBD_FULLCODE63_32);
*new_state = kbd_readl(keypad_data, OMAP4_KBD_FULLCODE31_0);
*(new_state + 1) = kbd_readl(keypad_data, OMAP4_KBD_FULLCODE63_32);
for (row = 0; row < keypad_data->rows; row++) {
changed = key_state[row] ^ keypad_data->key_state[row];
@ -121,12 +153,13 @@ static irqreturn_t omap4_keypad_interrupt(int irq, void *dev_id)
sizeof(keypad_data->key_state));
/* clear pending interrupts */
__raw_writel(__raw_readl(keypad_data->base + OMAP4_KBD_IRQSTATUS),
keypad_data->base + OMAP4_KBD_IRQSTATUS);
kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQSTATUS,
kbd_read_irqreg(keypad_data, OMAP4_KBD_IRQSTATUS));
/* enable interrupts */
__raw_writel(OMAP4_DEF_IRQENABLE_EVENTEN | OMAP4_DEF_IRQENABLE_LONGKEY,
keypad_data->base + OMAP4_KBD_IRQENABLE);
kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQENABLE,
OMAP4_DEF_IRQENABLE_EVENTEN |
OMAP4_DEF_IRQENABLE_LONGKEY);
return IRQ_HANDLED;
}
@ -139,16 +172,17 @@ static int omap4_keypad_open(struct input_dev *input)
disable_irq(keypad_data->irq);
__raw_writel(OMAP4_VAL_FUNCTIONALCFG,
keypad_data->base + OMAP4_KBD_CTRL);
__raw_writel(OMAP4_VAL_DEBOUNCINGTIME,
keypad_data->base + OMAP4_KBD_DEBOUNCINGTIME);
__raw_writel(OMAP4_VAL_IRQDISABLE,
keypad_data->base + OMAP4_KBD_IRQSTATUS);
__raw_writel(OMAP4_DEF_IRQENABLE_EVENTEN | OMAP4_DEF_IRQENABLE_LONGKEY,
keypad_data->base + OMAP4_KBD_IRQENABLE);
__raw_writel(OMAP4_DEF_WUP_EVENT_ENA | OMAP4_DEF_WUP_LONG_KEY_ENA,
keypad_data->base + OMAP4_KBD_WAKEUPENABLE);
kbd_writel(keypad_data, OMAP4_KBD_CTRL,
OMAP4_VAL_FUNCTIONALCFG);
kbd_writel(keypad_data, OMAP4_KBD_DEBOUNCINGTIME,
OMAP4_VAL_DEBOUNCINGTIME);
kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQSTATUS,
OMAP4_VAL_IRQDISABLE);
kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQENABLE,
OMAP4_DEF_IRQENABLE_EVENTEN |
OMAP4_DEF_IRQENABLE_LONGKEY);
kbd_writel(keypad_data, OMAP4_KBD_WAKEUPENABLE,
OMAP4_DEF_WUP_EVENT_ENA | OMAP4_DEF_WUP_LONG_KEY_ENA);
enable_irq(keypad_data->irq);
@ -162,12 +196,12 @@ static void omap4_keypad_close(struct input_dev *input)
disable_irq(keypad_data->irq);
/* Disable interrupts */
__raw_writel(OMAP4_VAL_IRQDISABLE,
keypad_data->base + OMAP4_KBD_IRQENABLE);
kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQENABLE,
OMAP4_VAL_IRQDISABLE);
/* clear pending interrupts */
__raw_writel(__raw_readl(keypad_data->base + OMAP4_KBD_IRQSTATUS),
keypad_data->base + OMAP4_KBD_IRQSTATUS);
kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQSTATUS,
kbd_read_irqreg(keypad_data, OMAP4_KBD_IRQSTATUS));
enable_irq(keypad_data->irq);
@ -182,6 +216,7 @@ static int __devinit omap4_keypad_probe(struct platform_device *pdev)
struct resource *res;
resource_size_t size;
unsigned int row_shift, max_keys;
int rev;
int irq;
int error;
@ -241,11 +276,40 @@ static int __devinit omap4_keypad_probe(struct platform_device *pdev)
keypad_data->rows = pdata->rows;
keypad_data->cols = pdata->cols;
/*
* Enable clocks for the keypad module so that we can read
* revision register.
*/
pm_runtime_enable(&pdev->dev);
error = pm_runtime_get_sync(&pdev->dev);
if (error) {
dev_err(&pdev->dev, "pm_runtime_get_sync() failed\n");
goto err_unmap;
}
rev = __raw_readl(keypad_data->base + OMAP4_KBD_REVISION);
rev &= 0x03 << 30;
rev >>= 30;
switch (rev) {
case KBD_REVISION_OMAP4:
keypad_data->reg_offset = 0x00;
keypad_data->irqreg_offset = 0x00;
break;
case KBD_REVISION_OMAP5:
keypad_data->reg_offset = 0x10;
keypad_data->irqreg_offset = 0x0c;
break;
default:
dev_err(&pdev->dev,
"Keypad reports unsupported revision %d", rev);
error = -EINVAL;
goto err_pm_put_sync;
}
/* input device allocation */
keypad_data->input = input_dev = input_allocate_device();
if (!input_dev) {
error = -ENOMEM;
goto err_unmap;
goto err_pm_put_sync;
}
input_dev->name = pdev->name;
@ -258,20 +322,19 @@ static int __devinit omap4_keypad_probe(struct platform_device *pdev)
input_dev->open = omap4_keypad_open;
input_dev->close = omap4_keypad_close;
input_dev->keycode = keypad_data->keymap;
input_dev->keycodesize = sizeof(keypad_data->keymap[0]);
input_dev->keycodemax = max_keys;
error = matrix_keypad_build_keymap(pdata->keymap_data, NULL,
pdata->rows, pdata->cols,
keypad_data->keymap, input_dev);
if (error) {
dev_err(&pdev->dev, "failed to build keymap\n");
goto err_free_input;
}
__set_bit(EV_KEY, input_dev->evbit);
__set_bit(EV_REP, input_dev->evbit);
input_set_capability(input_dev, EV_MSC, MSC_SCAN);
input_set_drvdata(input_dev, keypad_data);
matrix_keypad_build_keymap(pdata->keymap_data, row_shift,
input_dev->keycode, input_dev->keybit);
error = request_irq(keypad_data->irq, omap4_keypad_interrupt,
IRQF_TRIGGER_RISING,
"omap4-keypad", keypad_data);
@ -280,7 +343,7 @@ static int __devinit omap4_keypad_probe(struct platform_device *pdev)
goto err_free_input;
}
pm_runtime_enable(&pdev->dev);
pm_runtime_put_sync(&pdev->dev);
error = input_register_device(keypad_data->input);
if (error < 0) {
@ -296,6 +359,8 @@ err_pm_disable:
free_irq(keypad_data->irq, keypad_data);
err_free_input:
input_free_device(input_dev);
err_pm_put_sync:
pm_runtime_put_sync(&pdev->dev);
err_unmap:
iounmap(keypad_data->base);
err_release_mem:

View File

@ -626,21 +626,21 @@ static int __devinit pmic8xxx_kp_probe(struct platform_device *pdev)
kp->input->id.product = 0x0001;
kp->input->id.vendor = 0x0001;
kp->input->evbit[0] = BIT_MASK(EV_KEY);
if (pdata->rep)
__set_bit(EV_REP, kp->input->evbit);
kp->input->keycode = kp->keycodes;
kp->input->keycodemax = PM8XXX_MATRIX_MAX_SIZE;
kp->input->keycodesize = sizeof(kp->keycodes);
kp->input->open = pmic8xxx_kp_open;
kp->input->close = pmic8xxx_kp_close;
matrix_keypad_build_keymap(keymap_data, PM8XXX_ROW_SHIFT,
kp->input->keycode, kp->input->keybit);
rc = matrix_keypad_build_keymap(keymap_data, NULL,
PM8XXX_MAX_ROWS, PM8XXX_MAX_COLS,
kp->keycodes, kp->input);
if (rc) {
dev_err(&pdev->dev, "failed to build keymap\n");
goto err_get_irq;
}
if (pdata->rep)
__set_bit(EV_REP, kp->input->evbit);
input_set_capability(kp->input, EV_MSC, MSC_SCAN);
input_set_drvdata(kp->input, kp);
/* initialize keypad state */

View File

@ -454,23 +454,23 @@ static int __devinit samsung_keypad_probe(struct platform_device *pdev)
input_dev->name = pdev->name;
input_dev->id.bustype = BUS_HOST;
input_dev->dev.parent = &pdev->dev;
input_set_drvdata(input_dev, keypad);
input_dev->open = samsung_keypad_open;
input_dev->close = samsung_keypad_close;
input_dev->evbit[0] = BIT_MASK(EV_KEY);
if (!pdata->no_autorepeat)
input_dev->evbit[0] |= BIT_MASK(EV_REP);
error = matrix_keypad_build_keymap(keymap_data, NULL,
pdata->rows, pdata->cols,
keypad->keycodes, input_dev);
if (error) {
dev_err(&pdev->dev, "failed to build keymap\n");
goto err_put_clk;
}
input_set_capability(input_dev, EV_MSC, MSC_SCAN);
if (!pdata->no_autorepeat)
__set_bit(EV_REP, input_dev->evbit);
input_dev->keycode = keypad->keycodes;
input_dev->keycodesize = sizeof(keypad->keycodes[0]);
input_dev->keycodemax = pdata->rows << row_shift;
matrix_keypad_build_keymap(keymap_data, row_shift,
input_dev->keycode, input_dev->keybit);
input_set_drvdata(input_dev, keypad);
keypad->irq = platform_get_irq(pdev, 0);
if (keypad->irq < 0) {

View File

@ -19,6 +19,7 @@
#include <linux/irq.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm_wakeup.h>
#include <linux/slab.h>
@ -49,7 +50,9 @@
#define KEY_VALUE 0x00FFFFFF
#define ROW_MASK 0xF0
#define COLUMN_MASK 0x0F
#define ROW_SHIFT 4
#define NUM_ROWS 16
#define NUM_COLS 16
#define KEY_MATRIX_SHIFT 6
struct spear_kbd {
@ -60,7 +63,8 @@ struct spear_kbd {
unsigned int irq;
unsigned int mode;
unsigned short last_key;
unsigned short keycodes[256];
unsigned short keycodes[NUM_ROWS * NUM_COLS];
bool rep;
};
static irqreturn_t spear_kbd_interrupt(int irq, void *dev_id)
@ -136,27 +140,49 @@ static void spear_kbd_close(struct input_dev *dev)
kbd->last_key = KEY_RESERVED;
}
#ifdef CONFIG_OF
static int __devinit spear_kbd_parse_dt(struct platform_device *pdev,
struct spear_kbd *kbd)
{
struct device_node *np = pdev->dev.of_node;
int error;
u32 val;
if (!np) {
dev_err(&pdev->dev, "Missing DT data\n");
return -EINVAL;
}
if (of_property_read_bool(np, "autorepeat"))
kbd->rep = true;
error = of_property_read_u32(np, "st,mode", &val);
if (error) {
dev_err(&pdev->dev, "DT: Invalid or missing mode\n");
return error;
}
kbd->mode = val;
return 0;
}
#else
static inline int spear_kbd_parse_dt(struct platform_device *pdev,
struct spear_kbd *kbd)
{
return -ENOSYS;
}
#endif
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 kbd_platform_data *pdata = dev_get_platdata(&pdev->dev);
const struct matrix_keymap_data *keymap = pdata ? pdata->keymap : NULL;
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");
@ -179,7 +205,15 @@ static int __devinit spear_kbd_probe(struct platform_device *pdev)
kbd->input = input_dev;
kbd->irq = irq;
kbd->mode = pdata->mode;
if (!pdata) {
error = spear_kbd_parse_dt(pdev, kbd);
if (error)
goto err_free_mem;
} else {
kbd->mode = pdata->mode;
kbd->rep = pdata->rep;
}
kbd->res = request_mem_region(res->start, resource_size(res),
pdev->name);
@ -212,18 +246,17 @@ static int __devinit spear_kbd_probe(struct platform_device *pdev)
input_dev->open = spear_kbd_open;
input_dev->close = spear_kbd_close;
__set_bit(EV_KEY, input_dev->evbit);
if (pdata->rep)
error = matrix_keypad_build_keymap(keymap, NULL, NUM_ROWS, NUM_COLS,
kbd->keycodes, input_dev);
if (error) {
dev_err(&pdev->dev, "Failed to build keymap\n");
goto err_put_clk;
}
if (kbd->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);
@ -317,6 +350,14 @@ static int spear_kbd_resume(struct device *dev)
static SIMPLE_DEV_PM_OPS(spear_kbd_pm_ops, spear_kbd_suspend, spear_kbd_resume);
#ifdef CONFIG_OF
static const struct of_device_id spear_kbd_id_table[] = {
{ .compatible = "st,spear300-kbd" },
{}
};
MODULE_DEVICE_TABLE(of, spear_kbd_id_table);
#endif
static struct platform_driver spear_kbd_driver = {
.probe = spear_kbd_probe,
.remove = __devexit_p(spear_kbd_remove),
@ -324,6 +365,7 @@ static struct platform_driver spear_kbd_driver = {
.name = "keyboard",
.owner = THIS_MODULE,
.pm = &spear_kbd_pm_ops,
.of_match_table = of_match_ptr(spear_kbd_id_table),
},
};
module_platform_driver(spear_kbd_driver);

View File

@ -289,19 +289,17 @@ static int __devinit stmpe_keypad_probe(struct platform_device *pdev)
input->id.bustype = BUS_I2C;
input->dev.parent = &pdev->dev;
input_set_capability(input, EV_MSC, MSC_SCAN);
ret = matrix_keypad_build_keymap(plat->keymap_data, NULL,
STMPE_KEYPAD_MAX_ROWS,
STMPE_KEYPAD_MAX_COLS,
keypad->keymap, input);
if (ret)
goto out_freeinput;
__set_bit(EV_KEY, input->evbit);
input_set_capability(input, EV_MSC, MSC_SCAN);
if (!plat->no_autorepeat)
__set_bit(EV_REP, input->evbit);
input->keycode = keypad->keymap;
input->keycodesize = sizeof(keypad->keymap[0]);
input->keycodemax = ARRAY_SIZE(keypad->keymap);
matrix_keypad_build_keymap(plat->keymap_data, STMPE_KEYPAD_ROW_SHIFT,
input->keycode, input->keybit);
for (i = 0; i < plat->keymap_data->keymap_size; i++) {
unsigned int key = plat->keymap_data->keymap[i];

View File

@ -170,15 +170,4 @@ static struct serio_driver skbd_drv = {
.disconnect = skbd_disconnect,
};
static int __init skbd_init(void)
{
return serio_register_driver(&skbd_drv);
}
static void __exit skbd_exit(void)
{
serio_unregister_driver(&skbd_drv);
}
module_init(skbd_init);
module_exit(skbd_exit);
module_serio_driver(skbd_drv);

View File

@ -369,19 +369,4 @@ static struct serio_driver sunkbd_drv = {
.disconnect = sunkbd_disconnect,
};
/*
* The functions for insering/removing us as a module.
*/
static int __init sunkbd_init(void)
{
return serio_register_driver(&sunkbd_drv);
}
static void __exit sunkbd_exit(void)
{
serio_unregister_driver(&sunkbd_drv);
}
module_init(sunkbd_init);
module_exit(sunkbd_exit);
module_serio_driver(sunkbd_drv);

View File

@ -78,7 +78,7 @@
* @input: pointer to input device object
* @board: keypad platform device
* @krow: number of rows
* @kcol: number of coloumns
* @kcol: number of columns
* @keymap: matrix scan code table for keycodes
* @keypad_stopped: holds keypad status
*/
@ -96,21 +96,15 @@ static int tc3589x_keypad_init_key_hardware(struct tc_keypad *keypad)
{
int ret;
struct tc3589x *tc3589x = keypad->tc3589x;
u8 settle_time = keypad->board->settle_time;
u8 dbounce_period = keypad->board->debounce_period;
u8 rows = keypad->board->krow & 0xf; /* mask out the nibble */
u8 column = keypad->board->kcol & 0xf; /* mask out the nibble */
const struct tc3589x_keypad_platform_data *board = keypad->board;
/* validate platform configurations */
if (keypad->board->kcol > TC3589x_MAX_KPCOL ||
keypad->board->krow > TC3589x_MAX_KPROW ||
keypad->board->debounce_period > TC3589x_MAX_DEBOUNCE_SETTLE ||
keypad->board->settle_time > TC3589x_MAX_DEBOUNCE_SETTLE)
/* validate platform configuration */
if (board->kcol > TC3589x_MAX_KPCOL || board->krow > TC3589x_MAX_KPROW)
return -EINVAL;
/* configure KBDSIZE 4 LSbits for cols and 4 MSbits for rows */
ret = tc3589x_reg_write(tc3589x, TC3589x_KBDSIZE,
(rows << KP_ROW_SHIFT) | column);
(board->krow << KP_ROW_SHIFT) | board->kcol);
if (ret < 0)
return ret;
@ -124,12 +118,14 @@ static int tc3589x_keypad_init_key_hardware(struct tc_keypad *keypad)
return ret;
/* Configure settle time */
ret = tc3589x_reg_write(tc3589x, TC3589x_KBDSETTLE_REG, settle_time);
ret = tc3589x_reg_write(tc3589x, TC3589x_KBDSETTLE_REG,
board->settle_time);
if (ret < 0)
return ret;
/* Configure debounce time */
ret = tc3589x_reg_write(tc3589x, TC3589x_KBDBOUNCE, dbounce_period);
ret = tc3589x_reg_write(tc3589x, TC3589x_KBDBOUNCE,
board->debounce_period);
if (ret < 0)
return ret;
@ -337,23 +333,22 @@ static int __devinit tc3589x_keypad_probe(struct platform_device *pdev)
input->name = pdev->name;
input->dev.parent = &pdev->dev;
input->keycode = keypad->keymap;
input->keycodesize = sizeof(keypad->keymap[0]);
input->keycodemax = ARRAY_SIZE(keypad->keymap);
input->open = tc3589x_keypad_open;
input->close = tc3589x_keypad_close;
input_set_drvdata(input, keypad);
error = matrix_keypad_build_keymap(plat->keymap_data, NULL,
TC3589x_MAX_KPROW, TC3589x_MAX_KPCOL,
keypad->keymap, input);
if (error) {
dev_err(&pdev->dev, "Failed to build keymap\n");
goto err_free_mem;
}
input_set_capability(input, EV_MSC, MSC_SCAN);
__set_bit(EV_KEY, input->evbit);
if (!plat->no_autorepeat)
__set_bit(EV_REP, input->evbit);
matrix_keypad_build_keymap(plat->keymap_data, 0x3,
input->keycode, input->keybit);
input_set_drvdata(input, keypad);
error = request_threaded_irq(irq, NULL,
tc3589x_keypad_irq, plat->irqtype,

View File

@ -342,21 +342,20 @@ static int __devinit tca8418_keypad_probe(struct i2c_client *client,
input->id.product = 0x001;
input->id.version = 0x0001;
input->keycode = keypad_data->keymap;
input->keycodesize = sizeof(keypad_data->keymap[0]);
input->keycodemax = max_keys;
error = matrix_keypad_build_keymap(pdata->keymap_data, NULL,
pdata->rows, pdata->cols,
keypad_data->keymap, input);
if (error) {
dev_dbg(&client->dev, "Failed to build keymap\n");
goto fail2;
}
__set_bit(EV_KEY, input->evbit);
if (pdata->rep)
__set_bit(EV_REP, input->evbit);
input_set_capability(input, EV_MSC, MSC_SCAN);
input_set_drvdata(input, keypad_data);
matrix_keypad_build_keymap(pdata->keymap_data, row_shift,
input->keycode, input->keybit);
if (pdata->irq_is_gpio)
client->irq = gpio_to_irq(client->irq);

View File

@ -619,8 +619,8 @@ tegra_kbc_check_pin_cfg(const struct tegra_kbc_platform_data *pdata,
}
#ifdef CONFIG_OF
static struct tegra_kbc_platform_data * __devinit
tegra_kbc_dt_parse_pdata(struct platform_device *pdev)
static struct tegra_kbc_platform_data * __devinit tegra_kbc_dt_parse_pdata(
struct platform_device *pdev)
{
struct tegra_kbc_platform_data *pdata;
struct device_node *np = pdev->dev.of_node;
@ -660,10 +660,6 @@ tegra_kbc_dt_parse_pdata(struct platform_device *pdev)
pdata->pin_cfg[KBC_MAX_ROW + i].type = PIN_CFG_COL;
}
pdata->keymap_data = matrix_keyboard_of_fill_keymap(np, "linux,keymap");
/* FIXME: Add handling of linux,fn-keymap here */
return pdata;
}
#else
@ -674,10 +670,36 @@ static inline struct tegra_kbc_platform_data *tegra_kbc_dt_parse_pdata(
}
#endif
static int __devinit tegra_kbd_setup_keymap(struct tegra_kbc *kbc)
{
const struct tegra_kbc_platform_data *pdata = kbc->pdata;
const struct matrix_keymap_data *keymap_data = pdata->keymap_data;
unsigned int keymap_rows = KBC_MAX_KEY;
int retval;
if (keymap_data && pdata->use_fn_map)
keymap_rows *= 2;
retval = matrix_keypad_build_keymap(keymap_data, NULL,
keymap_rows, KBC_MAX_COL,
kbc->keycode, kbc->idev);
if (retval == -ENOSYS || retval == -ENOENT) {
/*
* If there is no OF support in kernel or keymap
* property is missing, use default keymap.
*/
retval = matrix_keypad_build_keymap(
&tegra_kbc_default_keymap_data, NULL,
keymap_rows, KBC_MAX_COL,
kbc->keycode, kbc->idev);
}
return retval;
}
static int __devinit tegra_kbc_probe(struct platform_device *pdev)
{
const struct tegra_kbc_platform_data *pdata = pdev->dev.platform_data;
const struct matrix_keymap_data *keymap_data;
struct tegra_kbc *kbc;
struct input_dev *input_dev;
struct resource *res;
@ -757,29 +779,26 @@ static int __devinit tegra_kbc_probe(struct platform_device *pdev)
kbc->repoll_dly = KBC_ROW_SCAN_DLY + scan_time_rows + pdata->repeat_cnt;
kbc->repoll_dly = DIV_ROUND_UP(kbc->repoll_dly, KBC_CYCLE_MS);
kbc->wakeup_key = pdata->wakeup_key;
kbc->use_fn_map = pdata->use_fn_map;
kbc->use_ghost_filter = pdata->use_ghost_filter;
input_dev->name = pdev->name;
input_dev->id.bustype = BUS_HOST;
input_dev->dev.parent = &pdev->dev;
input_dev->open = tegra_kbc_open;
input_dev->close = tegra_kbc_close;
input_set_drvdata(input_dev, kbc);
err = tegra_kbd_setup_keymap(kbc);
if (err) {
dev_err(&pdev->dev, "failed to setup keymap\n");
goto err_put_clk;
}
input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
__set_bit(EV_REP, input_dev->evbit);
input_set_capability(input_dev, EV_MSC, MSC_SCAN);
input_dev->keycode = kbc->keycode;
input_dev->keycodesize = sizeof(kbc->keycode[0]);
input_dev->keycodemax = KBC_MAX_KEY;
if (pdata->use_fn_map)
input_dev->keycodemax *= 2;
kbc->use_fn_map = pdata->use_fn_map;
kbc->use_ghost_filter = pdata->use_ghost_filter;
keymap_data = pdata->keymap_data ?: &tegra_kbc_default_keymap_data;
matrix_keypad_build_keymap(keymap_data, KBC_ROW_SHIFT,
input_dev->keycode, input_dev->keybit);
kbc->wakeup_key = pdata->wakeup_key;
input_set_drvdata(input_dev, kbc);
err = request_irq(kbc->irq, tegra_kbc_isr,
IRQF_NO_SUSPEND | IRQF_TRIGGER_HIGH, pdev->name, kbc);
@ -799,9 +818,6 @@ static int __devinit tegra_kbc_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, kbc);
device_init_wakeup(&pdev->dev, pdata->wakeup);
if (!pdev->dev.platform_data)
matrix_keyboard_of_free_keymap(pdata->keymap_data);
return 0;
err_free_irq:
@ -816,10 +832,8 @@ err_free_mem:
input_free_device(input_dev);
kfree(kbc);
err_free_pdata:
if (!pdev->dev.platform_data) {
matrix_keyboard_of_free_keymap(pdata->keymap_data);
if (!pdev->dev.platform_data)
kfree(pdata);
}
return err;
}

View File

@ -247,15 +247,11 @@ static int __devinit keypad_probe(struct platform_device *pdev)
error = -ENOMEM;
goto error_input;
}
input_set_drvdata(kp->input_dev, kp);
kp->input_dev->name = pdev->name;
kp->input_dev->dev.parent = &pdev->dev;
kp->input_dev->open = keypad_start;
kp->input_dev->close = keypad_stop;
kp->input_dev->evbit[0] = BIT_MASK(EV_KEY);
if (!pdata->no_autorepeat)
kp->input_dev->evbit[0] |= BIT_MASK(EV_REP);
clk_enable(kp->clk);
rev = keypad_read(kp, rev);
@ -264,15 +260,20 @@ static int __devinit keypad_probe(struct platform_device *pdev)
kp->input_dev->id.version = ((rev >> 16) & 0xfff);
clk_disable(kp->clk);
kp->input_dev->keycode = kp->keycodes;
kp->input_dev->keycodesize = sizeof(kp->keycodes[0]);
kp->input_dev->keycodemax = kp->rows << kp->row_shift;
matrix_keypad_build_keymap(keymap_data, kp->row_shift, kp->keycodes,
kp->input_dev->keybit);
error = matrix_keypad_build_keymap(keymap_data, NULL,
kp->rows, kp->cols,
kp->keycodes, kp->input_dev);
if (error) {
dev_err(dev, "Failed to build keymap\n");
goto error_reg;
}
if (!pdata->no_autorepeat)
kp->input_dev->evbit[0] |= BIT_MASK(EV_REP);
input_set_capability(kp->input_dev, EV_MSC, MSC_SCAN);
input_set_drvdata(kp->input_dev, kp);
error = input_register_device(kp->input_dev);
if (error < 0) {
dev_err(dev, "Could not register input device\n");

View File

@ -361,14 +361,6 @@ static int __devinit twl4030_kp_probe(struct platform_device *pdev)
kp->irq = platform_get_irq(pdev, 0);
/* setup input device */
__set_bit(EV_KEY, input->evbit);
/* Enable auto repeat feature of Linux input subsystem */
if (pdata->rep)
__set_bit(EV_REP, input->evbit);
input_set_capability(input, EV_MSC, MSC_SCAN);
input->name = "TWL4030 Keypad";
input->phys = "twl4030_keypad/input0";
input->dev.parent = &pdev->dev;
@ -378,12 +370,19 @@ static int __devinit twl4030_kp_probe(struct platform_device *pdev)
input->id.product = 0x0001;
input->id.version = 0x0003;
input->keycode = kp->keymap;
input->keycodesize = sizeof(kp->keymap[0]);
input->keycodemax = ARRAY_SIZE(kp->keymap);
error = matrix_keypad_build_keymap(keymap_data, NULL,
TWL4030_MAX_ROWS,
1 << TWL4030_ROW_SHIFT,
kp->keymap, input);
if (error) {
dev_err(kp->dbg_dev, "Failed to build keymap\n");
goto err1;
}
matrix_keypad_build_keymap(keymap_data, TWL4030_ROW_SHIFT,
input->keycode, input->keybit);
input_set_capability(input, EV_MSC, MSC_SCAN);
/* Enable auto repeat feature of Linux input subsystem */
if (pdata->rep)
__set_bit(EV_REP, input->evbit);
error = input_register_device(input);
if (error) {

View File

@ -42,7 +42,8 @@
#define KGET_RAW(n) (((n) & KEY0R) >> 3)
#define KGET_COLUMN(n) ((n) & KEY0C)
#define W90P910_MAX_KEY_NUM (8 * 8)
#define W90P910_NUM_ROWS 8
#define W90P910_NUM_COLS 8
#define W90P910_ROW_SHIFT 3
struct w90p910_keypad {
@ -51,7 +52,7 @@ struct w90p910_keypad {
struct input_dev *input_dev;
void __iomem *mmio_base;
int irq;
unsigned short keymap[W90P910_MAX_KEY_NUM];
unsigned short keymap[W90P910_NUM_ROWS * W90P910_NUM_COLS];
};
static void w90p910_keypad_scan_matrix(struct w90p910_keypad *keypad,
@ -190,17 +191,13 @@ static int __devinit w90p910_keypad_probe(struct platform_device *pdev)
input_dev->close = w90p910_keypad_close;
input_dev->dev.parent = &pdev->dev;
input_dev->keycode = keypad->keymap;
input_dev->keycodesize = sizeof(keypad->keymap[0]);
input_dev->keycodemax = ARRAY_SIZE(keypad->keymap);
input_set_drvdata(input_dev, keypad);
input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
input_set_capability(input_dev, EV_MSC, MSC_SCAN);
matrix_keypad_build_keymap(keymap_data, W90P910_ROW_SHIFT,
input_dev->keycode, input_dev->keybit);
error = matrix_keypad_build_keymap(keymap_data, NULL,
W90P910_NUM_ROWS, W90P910_NUM_COLS,
keypad->keymap, input_dev);
if (error) {
dev_err(&pdev->dev, "failed to build keymap\n");
goto failed_put_clk;
}
error = request_irq(keypad->irq, w90p910_keypad_irq_handler,
0, pdev->name, keypad);
@ -209,6 +206,10 @@ static int __devinit w90p910_keypad_probe(struct platform_device *pdev)
goto failed_put_clk;
}
__set_bit(EV_REP, input_dev->evbit);
input_set_capability(input_dev, EV_MSC, MSC_SCAN);
input_set_drvdata(input_dev, keypad);
/* Register the input device */
error = input_register_device(input_dev);
if (error) {

View File

@ -169,15 +169,4 @@ static struct serio_driver xtkbd_drv = {
.disconnect = xtkbd_disconnect,
};
static int __init xtkbd_init(void)
{
return serio_register_driver(&xtkbd_drv);
}
static void __exit xtkbd_exit(void)
{
serio_unregister_driver(&xtkbd_drv);
}
module_init(xtkbd_init);
module_exit(xtkbd_exit);
module_serio_driver(xtkbd_drv);

View File

@ -0,0 +1,163 @@
/*
* Helpers for matrix keyboard bindings
*
* Copyright (C) 2012 Google, Inc
*
* Author:
* Olof Johansson <olof@lixom.net>
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/input.h>
#include <linux/of.h>
#include <linux/export.h>
#include <linux/input/matrix_keypad.h>
static bool matrix_keypad_map_key(struct input_dev *input_dev,
unsigned int rows, unsigned int cols,
unsigned int row_shift, unsigned int key)
{
unsigned short *keymap = input_dev->keycode;
unsigned int row = KEY_ROW(key);
unsigned int col = KEY_COL(key);
unsigned short code = KEY_VAL(key);
if (row >= rows || col >= cols) {
dev_err(input_dev->dev.parent,
"%s: invalid keymap entry 0x%x (row: %d, col: %d, rows: %d, cols: %d)\n",
__func__, key, row, col, rows, cols);
return false;
}
keymap[MATRIX_SCAN_CODE(row, col, row_shift)] = code;
__set_bit(code, input_dev->keybit);
return true;
}
#ifdef CONFIG_OF
static int matrix_keypad_parse_of_keymap(const char *propname,
unsigned int rows, unsigned int cols,
struct input_dev *input_dev)
{
struct device *dev = input_dev->dev.parent;
struct device_node *np = dev->of_node;
unsigned int row_shift = get_count_order(cols);
unsigned int max_keys = rows << row_shift;
unsigned int proplen, i, size;
const __be32 *prop;
if (!np)
return -ENOENT;
if (!propname)
propname = "linux,keymap";
prop = of_get_property(np, propname, &proplen);
if (!prop) {
dev_err(dev, "OF: %s property not defined in %s\n",
propname, np->full_name);
return -ENOENT;
}
if (proplen % sizeof(u32)) {
dev_err(dev, "OF: Malformed keycode property %s in %s\n",
propname, np->full_name);
return -EINVAL;
}
size = proplen / sizeof(u32);
if (size > max_keys) {
dev_err(dev, "OF: %s size overflow\n", propname);
return -EINVAL;
}
for (i = 0; i < size; i++) {
unsigned int key = be32_to_cpup(prop + i);
if (!matrix_keypad_map_key(input_dev, rows, cols,
row_shift, key))
return -EINVAL;
}
return 0;
}
#else
static int matrix_keypad_parse_of_keymap(const char *propname,
unsigned int rows, unsigned int cols,
struct input_dev *input_dev)
{
return -ENOSYS;
}
#endif
/**
* matrix_keypad_build_keymap - convert platform keymap into matrix keymap
* @keymap_data: keymap supplied by the platform code
* @keymap_name: name of device tree property containing keymap (if device
* tree support is enabled).
* @rows: number of rows in target keymap array
* @cols: number of cols in target keymap array
* @keymap: expanded version of keymap that is suitable for use by
* matrix keyboard driver
* @input_dev: input devices for which we are setting up the keymap
*
* This function converts platform keymap (encoded with KEY() macro) into
* an array of keycodes that is suitable for using in a standard matrix
* keyboard driver that uses row and col as indices.
*
* If @keymap_data is not supplied and device tree support is enabled
* it will attempt load the keymap from property specified by @keymap_name
* argument (or "linux,keymap" if @keymap_name is %NULL).
*
* Callers are expected to set up input_dev->dev.parent before calling this
* function.
*/
int matrix_keypad_build_keymap(const struct matrix_keymap_data *keymap_data,
const char *keymap_name,
unsigned int rows, unsigned int cols,
unsigned short *keymap,
struct input_dev *input_dev)
{
unsigned int row_shift = get_count_order(cols);
int i;
int error;
input_dev->keycode = keymap;
input_dev->keycodesize = sizeof(*keymap);
input_dev->keycodemax = rows << row_shift;
__set_bit(EV_KEY, input_dev->evbit);
if (keymap_data) {
for (i = 0; i < keymap_data->keymap_size; i++) {
unsigned int key = keymap_data->keymap[i];
if (!matrix_keypad_map_key(input_dev, rows, cols,
row_shift, key))
return -EINVAL;
}
} else {
error = matrix_keypad_parse_of_keymap(keymap_name, rows, cols,
input_dev);
if (error)
return error;
}
__clear_bit(KEY_RESERVED, input_dev->keybit);
return 0;
}
EXPORT_SYMBOL(matrix_keypad_build_keymap);

View File

@ -318,7 +318,7 @@ struct cma3000_accl_data *cma3000_init(struct device *dev, int irq,
mutex_init(&data->mutex);
data->mode = pdata->mode;
if (data->mode < CMAMODE_DEFAULT || data->mode > CMAMODE_POFF) {
if (data->mode > CMAMODE_POFF) {
data->mode = CMAMODE_MOTDET;
dev_warn(dev,
"Invalid mode specified, assuming Motion Detect\n");

View File

@ -367,7 +367,7 @@ static int __devinit mpu3050_probe(struct i2c_client *client,
error = request_threaded_irq(client->irq,
NULL, mpu3050_interrupt_thread,
IRQF_TRIGGER_RISING,
IRQF_TRIGGER_RISING | IRQF_ONESHOT,
"mpu3050", sensor);
if (error) {
dev_err(&client->dev,

View File

@ -27,6 +27,7 @@
*/
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/workqueue.h>
#include <linux/input.h>
#include <linux/mfd/twl6040.h>
@ -258,10 +259,13 @@ static SIMPLE_DEV_PM_OPS(twl6040_vibra_pm_ops, twl6040_vibra_suspend, NULL);
static int __devinit twl6040_vibra_probe(struct platform_device *pdev)
{
struct twl6040_vibra_data *pdata = pdev->dev.platform_data;
struct device_node *node = pdev->dev.of_node;
struct vibra_info *info;
int vddvibl_uV = 0;
int vddvibr_uV = 0;
int ret;
if (!pdata) {
if (!pdata && !node) {
dev_err(&pdev->dev, "platform_data not available\n");
return -EINVAL;
}
@ -273,11 +277,26 @@ static int __devinit twl6040_vibra_probe(struct platform_device *pdev)
}
info->dev = &pdev->dev;
info->twl6040 = dev_get_drvdata(pdev->dev.parent);
info->vibldrv_res = pdata->vibldrv_res;
info->vibrdrv_res = pdata->vibrdrv_res;
info->viblmotor_res = pdata->viblmotor_res;
info->vibrmotor_res = pdata->vibrmotor_res;
if (pdata) {
info->vibldrv_res = pdata->vibldrv_res;
info->vibrdrv_res = pdata->vibrdrv_res;
info->viblmotor_res = pdata->viblmotor_res;
info->vibrmotor_res = pdata->vibrmotor_res;
vddvibl_uV = pdata->vddvibl_uV;
vddvibr_uV = pdata->vddvibr_uV;
} else {
of_property_read_u32(node, "vibldrv_res", &info->vibldrv_res);
of_property_read_u32(node, "vibrdrv_res", &info->vibrdrv_res);
of_property_read_u32(node, "viblmotor_res",
&info->viblmotor_res);
of_property_read_u32(node, "vibrmotor_res",
&info->vibrmotor_res);
of_property_read_u32(node, "vddvibl_uV", &vddvibl_uV);
of_property_read_u32(node, "vddvibr_uV", &vddvibr_uV);
}
if ((!info->vibldrv_res && !info->viblmotor_res) ||
(!info->vibrdrv_res && !info->vibrmotor_res)) {
dev_err(info->dev, "invalid vibra driver/motor resistance\n");
@ -339,10 +358,9 @@ static int __devinit twl6040_vibra_probe(struct platform_device *pdev)
goto err_regulator;
}
if (pdata->vddvibl_uV) {
if (vddvibl_uV) {
ret = regulator_set_voltage(info->supplies[0].consumer,
pdata->vddvibl_uV,
pdata->vddvibl_uV);
vddvibl_uV, vddvibl_uV);
if (ret) {
dev_err(info->dev, "failed to set VDDVIBL volt %d\n",
ret);
@ -350,10 +368,9 @@ static int __devinit twl6040_vibra_probe(struct platform_device *pdev)
}
}
if (pdata->vddvibr_uV) {
if (vddvibr_uV) {
ret = regulator_set_voltage(info->supplies[1].consumer,
pdata->vddvibr_uV,
pdata->vddvibr_uV);
vddvibr_uV, vddvibr_uV);
if (ret) {
dev_err(info->dev, "failed to set VDDVIBR volt %d\n",
ret);
@ -401,6 +418,12 @@ static int __devexit twl6040_vibra_remove(struct platform_device *pdev)
return 0;
}
static const struct of_device_id twl6040_vibra_of_match[] = {
{.compatible = "ti,twl6040-vibra", },
{ },
};
MODULE_DEVICE_TABLE(of, twl6040_vibra_of_match);
static struct platform_driver twl6040_vibra_driver = {
.probe = twl6040_vibra_probe,
.remove = __devexit_p(twl6040_vibra_remove),
@ -408,6 +431,7 @@ static struct platform_driver twl6040_vibra_driver = {
.name = "twl6040-vibra",
.owner = THIS_MODULE,
.pm = &twl6040_vibra_pm_ops,
.of_match_table = twl6040_vibra_of_match,
},
};
module_platform_driver(twl6040_vibra_driver);

View File

@ -339,4 +339,16 @@ config MOUSE_SYNAPTICS_USB
To compile this driver as a module, choose M here: the
module will be called synaptics_usb.
config MOUSE_NAVPOINT_PXA27x
tristate "Synaptics NavPoint (PXA27x SSP/SPI)"
depends on PXA27x && PXA_SSP
help
This driver adds support for the Synaptics NavPoint touchpad connected
to a PXA27x SSP port in SPI slave mode. The device emulates a mouse;
a tap or tap-and-a-half drag gesture emulates the left mouse button.
For example, use the xf86-input-evdev driver for an X pointing device.
To compile this driver as a module, choose M here: the
module will be called navpoint.
endif

View File

@ -12,6 +12,7 @@ obj-$(CONFIG_MOUSE_GPIO) += gpio_mouse.o
obj-$(CONFIG_MOUSE_INPORT) += inport.o
obj-$(CONFIG_MOUSE_LOGIBM) += logibm.o
obj-$(CONFIG_MOUSE_MAPLE) += maplemouse.o
obj-$(CONFIG_MOUSE_NAVPOINT_PXA27x) += navpoint.o
obj-$(CONFIG_MOUSE_PC110PAD) += pc110pad.o
obj-$(CONFIG_MOUSE_PS2) += psmouse.o
obj-$(CONFIG_MOUSE_PXA930_TRKBALL) += pxa930_trkball.o

View File

@ -553,10 +553,7 @@ static void alps_process_touchpad_packet_v3(struct psmouse *psmouse)
alps_report_semi_mt_data(dev, fingers, x1, y1, x2, y2);
input_report_key(dev, BTN_TOOL_FINGER, fingers == 1);
input_report_key(dev, BTN_TOOL_DOUBLETAP, fingers == 2);
input_report_key(dev, BTN_TOOL_TRIPLETAP, fingers == 3);
input_report_key(dev, BTN_TOOL_QUADTAP, fingers == 4);
input_mt_report_finger_count(dev, fingers);
input_report_key(dev, BTN_LEFT, left);
input_report_key(dev, BTN_RIGHT, right);
@ -604,10 +601,54 @@ static void alps_process_packet_v3(struct psmouse *psmouse)
static void alps_process_packet_v4(struct psmouse *psmouse)
{
struct alps_data *priv = psmouse->private;
unsigned char *packet = psmouse->packet;
struct input_dev *dev = psmouse->dev;
int offset;
int x, y, z;
int left, right;
int x1, y1, x2, y2;
int fingers = 0;
unsigned int x_bitmap, y_bitmap;
/*
* v4 has a 6-byte encoding for bitmap data, but this data is
* broken up between 3 normal packets. Use priv->multi_packet to
* track our position in the bitmap packet.
*/
if (packet[6] & 0x40) {
/* sync, reset position */
priv->multi_packet = 0;
}
if (WARN_ON_ONCE(priv->multi_packet > 2))
return;
offset = 2 * priv->multi_packet;
priv->multi_data[offset] = packet[6];
priv->multi_data[offset + 1] = packet[7];
if (++priv->multi_packet > 2) {
priv->multi_packet = 0;
x_bitmap = ((priv->multi_data[2] & 0x1f) << 10) |
((priv->multi_data[3] & 0x60) << 3) |
((priv->multi_data[0] & 0x3f) << 2) |
((priv->multi_data[1] & 0x60) >> 5);
y_bitmap = ((priv->multi_data[5] & 0x01) << 10) |
((priv->multi_data[3] & 0x1f) << 5) |
(priv->multi_data[1] & 0x1f);
fingers = alps_process_bitmap(x_bitmap, y_bitmap,
&x1, &y1, &x2, &y2);
/* Store MT data.*/
priv->fingers = fingers;
priv->x1 = x1;
priv->x2 = x2;
priv->y1 = y1;
priv->y2 = y2;
}
left = packet[4] & 0x01;
right = packet[4] & 0x02;
@ -617,21 +658,41 @@ static void alps_process_packet_v4(struct psmouse *psmouse)
y = ((packet[2] & 0x7f) << 4) | (packet[3] & 0x0f);
z = packet[5] & 0x7f;
/*
* If there were no contacts in the bitmap, use ST
* points in MT reports.
* If there were two contacts or more, report MT data.
*/
if (priv->fingers < 2) {
x1 = x;
y1 = y;
fingers = z > 0 ? 1 : 0;
} else {
fingers = priv->fingers;
x1 = priv->x1;
x2 = priv->x2;
y1 = priv->y1;
y2 = priv->y2;
}
if (z >= 64)
input_report_key(dev, BTN_TOUCH, 1);
else
input_report_key(dev, BTN_TOUCH, 0);
alps_report_semi_mt_data(dev, fingers, x1, y1, x2, y2);
input_mt_report_finger_count(dev, fingers);
input_report_key(dev, BTN_LEFT, left);
input_report_key(dev, BTN_RIGHT, right);
if (z > 0) {
input_report_abs(dev, ABS_X, x);
input_report_abs(dev, ABS_Y, y);
}
input_report_abs(dev, ABS_PRESSURE, z);
input_report_key(dev, BTN_TOOL_FINGER, z > 0);
input_report_key(dev, BTN_LEFT, left);
input_report_key(dev, BTN_RIGHT, right);
input_sync(dev);
}
@ -1557,6 +1618,7 @@ int alps_init(struct psmouse *psmouse)
input_set_abs_params(dev1, ABS_Y, 0, 767, 0, 0);
break;
case ALPS_PROTO_V3:
case ALPS_PROTO_V4:
set_bit(INPUT_PROP_SEMI_MT, dev1->propbit);
input_mt_init_slots(dev1, 2);
input_set_abs_params(dev1, ABS_MT_POSITION_X, 0, ALPS_V3_X_MAX, 0, 0);
@ -1565,8 +1627,7 @@ int alps_init(struct psmouse *psmouse)
set_bit(BTN_TOOL_DOUBLETAP, dev1->keybit);
set_bit(BTN_TOOL_TRIPLETAP, dev1->keybit);
set_bit(BTN_TOOL_QUADTAP, dev1->keybit);
/* fall through */
case ALPS_PROTO_V4:
input_set_abs_params(dev1, ABS_X, 0, ALPS_V3_X_MAX, 0, 0);
input_set_abs_params(dev1, ABS_Y, 0, ALPS_V3_Y_MAX, 0, 0);
break;

View File

@ -39,6 +39,8 @@ struct alps_data {
int prev_fin; /* Finger bit from previous packet */
int multi_packet; /* Multi-packet data in progress */
unsigned char multi_data[6]; /* Saved multi-packet data */
int x1, x2, y1, y2; /* Coordinates from last MT report */
int fingers; /* Number of fingers from MT report */
u8 quirks;
struct timer_list timer;
};

View File

@ -0,0 +1,369 @@
/*
* Synaptics NavPoint (PXA27x SSP/SPI) driver.
*
* Copyright (C) 2012 Paul Parsons <lost.distance@yahoo.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.
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/input.h>
#include <linux/input/navpoint.h>
#include <linux/interrupt.h>
#include <linux/mutex.h>
#include <linux/pxa2xx_ssp.h>
#include <linux/slab.h>
/*
* Synaptics Modular Embedded Protocol: Module Packet Format.
* Module header byte 2:0 = Length (# bytes that follow)
* Module header byte 4:3 = Control
* Module header byte 7:5 = Module Address
*/
#define HEADER_LENGTH(byte) ((byte) & 0x07)
#define HEADER_CONTROL(byte) (((byte) >> 3) & 0x03)
#define HEADER_ADDRESS(byte) ((byte) >> 5)
struct navpoint {
struct ssp_device *ssp;
struct input_dev *input;
struct device *dev;
int gpio;
int index;
u8 data[1 + HEADER_LENGTH(0xff)];
};
/*
* Initialization values for SSCR0_x, SSCR1_x, SSSR_x.
*/
static const u32 sscr0 = 0
| SSCR0_TUM /* TIM = 1; No TUR interrupts */
| SSCR0_RIM /* RIM = 1; No ROR interrupts */
| SSCR0_SSE /* SSE = 1; SSP enabled */
| SSCR0_Motorola /* FRF = 0; Motorola SPI */
| SSCR0_DataSize(16) /* DSS = 15; Data size = 16-bit */
;
static const u32 sscr1 = 0
| SSCR1_SCFR /* SCFR = 1; SSPSCLK only during transfers */
| SSCR1_SCLKDIR /* SCLKDIR = 1; Slave mode */
| SSCR1_SFRMDIR /* SFRMDIR = 1; Slave mode */
| SSCR1_RWOT /* RWOT = 1; Receive without transmit mode */
| SSCR1_RxTresh(1) /* RFT = 0; Receive FIFO threshold = 1 */
| SSCR1_SPH /* SPH = 1; SSPSCLK inactive 0.5 + 1 cycles */
| SSCR1_RIE /* RIE = 1; Receive FIFO interrupt enabled */
;
static const u32 sssr = 0
| SSSR_BCE /* BCE = 1; Clear BCE */
| SSSR_TUR /* TUR = 1; Clear TUR */
| SSSR_EOC /* EOC = 1; Clear EOC */
| SSSR_TINT /* TINT = 1; Clear TINT */
| SSSR_PINT /* PINT = 1; Clear PINT */
| SSSR_ROR /* ROR = 1; Clear ROR */
;
/*
* MEP Query $22: Touchpad Coordinate Range Query is not supported by
* the NavPoint module, so sampled values provide the default limits.
*/
#define NAVPOINT_X_MIN 1278
#define NAVPOINT_X_MAX 5340
#define NAVPOINT_Y_MIN 1572
#define NAVPOINT_Y_MAX 4396
#define NAVPOINT_PRESSURE_MIN 0
#define NAVPOINT_PRESSURE_MAX 255
static void navpoint_packet(struct navpoint *navpoint)
{
int finger;
int gesture;
int x, y, z;
switch (navpoint->data[0]) {
case 0xff: /* Garbage (packet?) between reset and Hello packet */
case 0x00: /* Module 0, NULL packet */
break;
case 0x0e: /* Module 0, Absolute packet */
finger = (navpoint->data[1] & 0x01);
gesture = (navpoint->data[1] & 0x02);
x = ((navpoint->data[2] & 0x1f) << 8) | navpoint->data[3];
y = ((navpoint->data[4] & 0x1f) << 8) | navpoint->data[5];
z = navpoint->data[6];
input_report_key(navpoint->input, BTN_TOUCH, finger);
input_report_abs(navpoint->input, ABS_X, x);
input_report_abs(navpoint->input, ABS_Y, y);
input_report_abs(navpoint->input, ABS_PRESSURE, z);
input_report_key(navpoint->input, BTN_TOOL_FINGER, finger);
input_report_key(navpoint->input, BTN_LEFT, gesture);
input_sync(navpoint->input);
break;
case 0x19: /* Module 0, Hello packet */
if ((navpoint->data[1] & 0xf0) == 0x10)
break;
/* FALLTHROUGH */
default:
dev_warn(navpoint->dev,
"spurious packet: data=0x%02x,0x%02x,...\n",
navpoint->data[0], navpoint->data[1]);
break;
}
}
static irqreturn_t navpoint_irq(int irq, void *dev_id)
{
struct navpoint *navpoint = dev_id;
struct ssp_device *ssp = navpoint->ssp;
irqreturn_t ret = IRQ_NONE;
u32 status;
status = pxa_ssp_read_reg(ssp, SSSR);
if (status & sssr) {
dev_warn(navpoint->dev,
"unexpected interrupt: status=0x%08x\n", status);
pxa_ssp_write_reg(ssp, SSSR, (status & sssr));
ret = IRQ_HANDLED;
}
while (status & SSSR_RNE) {
u32 data;
data = pxa_ssp_read_reg(ssp, SSDR);
navpoint->data[navpoint->index + 0] = (data >> 8);
navpoint->data[navpoint->index + 1] = data;
navpoint->index += 2;
if (HEADER_LENGTH(navpoint->data[0]) < navpoint->index) {
navpoint_packet(navpoint);
navpoint->index = 0;
}
status = pxa_ssp_read_reg(ssp, SSSR);
ret = IRQ_HANDLED;
}
return ret;
}
static void navpoint_up(struct navpoint *navpoint)
{
struct ssp_device *ssp = navpoint->ssp;
int timeout;
clk_prepare_enable(ssp->clk);
pxa_ssp_write_reg(ssp, SSCR1, sscr1);
pxa_ssp_write_reg(ssp, SSSR, sssr);
pxa_ssp_write_reg(ssp, SSTO, 0);
pxa_ssp_write_reg(ssp, SSCR0, sscr0); /* SSCR0_SSE written last */
/* Wait until SSP port is ready for slave clock operations */
for (timeout = 100; timeout != 0; --timeout) {
if (!(pxa_ssp_read_reg(ssp, SSSR) & SSSR_CSS))
break;
msleep(1);
}
if (timeout == 0)
dev_err(navpoint->dev,
"timeout waiting for SSSR[CSS] to clear\n");
if (gpio_is_valid(navpoint->gpio))
gpio_set_value(navpoint->gpio, 1);
}
static void navpoint_down(struct navpoint *navpoint)
{
struct ssp_device *ssp = navpoint->ssp;
if (gpio_is_valid(navpoint->gpio))
gpio_set_value(navpoint->gpio, 0);
pxa_ssp_write_reg(ssp, SSCR0, 0);
clk_disable_unprepare(ssp->clk);
}
static int navpoint_open(struct input_dev *input)
{
struct navpoint *navpoint = input_get_drvdata(input);
navpoint_up(navpoint);
return 0;
}
static void navpoint_close(struct input_dev *input)
{
struct navpoint *navpoint = input_get_drvdata(input);
navpoint_down(navpoint);
}
static int __devinit navpoint_probe(struct platform_device *pdev)
{
const struct navpoint_platform_data *pdata =
dev_get_platdata(&pdev->dev);
struct ssp_device *ssp;
struct input_dev *input;
struct navpoint *navpoint;
int error;
if (!pdata) {
dev_err(&pdev->dev, "no platform data\n");
return -EINVAL;
}
if (gpio_is_valid(pdata->gpio)) {
error = gpio_request_one(pdata->gpio, GPIOF_OUT_INIT_LOW,
"SYNAPTICS_ON");
if (error)
return error;
}
ssp = pxa_ssp_request(pdata->port, pdev->name);
if (!ssp) {
error = -ENODEV;
goto err_free_gpio;
}
/* HaRET does not disable devices before jumping into Linux */
if (pxa_ssp_read_reg(ssp, SSCR0) & SSCR0_SSE) {
pxa_ssp_write_reg(ssp, SSCR0, 0);
dev_warn(&pdev->dev, "ssp%d already enabled\n", pdata->port);
}
navpoint = kzalloc(sizeof(*navpoint), GFP_KERNEL);
input = input_allocate_device();
if (!navpoint || !input) {
error = -ENOMEM;
goto err_free_mem;
}
navpoint->ssp = ssp;
navpoint->input = input;
navpoint->dev = &pdev->dev;
navpoint->gpio = pdata->gpio;
input->name = pdev->name;
input->dev.parent = &pdev->dev;
__set_bit(EV_KEY, input->evbit);
__set_bit(EV_ABS, input->evbit);
__set_bit(BTN_LEFT, input->keybit);
__set_bit(BTN_TOUCH, input->keybit);
__set_bit(BTN_TOOL_FINGER, input->keybit);
input_set_abs_params(input, ABS_X,
NAVPOINT_X_MIN, NAVPOINT_X_MAX, 0, 0);
input_set_abs_params(input, ABS_Y,
NAVPOINT_Y_MIN, NAVPOINT_Y_MAX, 0, 0);
input_set_abs_params(input, ABS_PRESSURE,
NAVPOINT_PRESSURE_MIN, NAVPOINT_PRESSURE_MAX,
0, 0);
input->open = navpoint_open;
input->close = navpoint_close;
input_set_drvdata(input, navpoint);
error = request_irq(ssp->irq, navpoint_irq, 0, pdev->name, navpoint);
if (error)
goto err_free_mem;
error = input_register_device(input);
if (error)
goto err_free_irq;
platform_set_drvdata(pdev, navpoint);
dev_dbg(&pdev->dev, "ssp%d, irq %d\n", pdata->port, ssp->irq);
return 0;
err_free_irq:
free_irq(ssp->irq, &pdev->dev);
err_free_mem:
input_free_device(input);
kfree(navpoint);
pxa_ssp_free(ssp);
err_free_gpio:
if (gpio_is_valid(pdata->gpio))
gpio_free(pdata->gpio);
return error;
}
static int __devexit navpoint_remove(struct platform_device *pdev)
{
const struct navpoint_platform_data *pdata =
dev_get_platdata(&pdev->dev);
struct navpoint *navpoint = platform_get_drvdata(pdev);
struct ssp_device *ssp = navpoint->ssp;
free_irq(ssp->irq, navpoint);
input_unregister_device(navpoint->input);
kfree(navpoint);
pxa_ssp_free(ssp);
if (gpio_is_valid(pdata->gpio))
gpio_free(pdata->gpio);
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int navpoint_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct navpoint *navpoint = platform_get_drvdata(pdev);
struct input_dev *input = navpoint->input;
mutex_lock(&input->mutex);
if (input->users)
navpoint_down(navpoint);
mutex_unlock(&input->mutex);
return 0;
}
static int navpoint_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct navpoint *navpoint = platform_get_drvdata(pdev);
struct input_dev *input = navpoint->input;
mutex_lock(&input->mutex);
if (input->users)
navpoint_up(navpoint);
mutex_unlock(&input->mutex);
return 0;
}
#endif
static SIMPLE_DEV_PM_OPS(navpoint_pm_ops, navpoint_suspend, navpoint_resume);
static struct platform_driver navpoint_driver = {
.probe = navpoint_probe,
.remove = __devexit_p(navpoint_remove),
.driver = {
.name = "navpoint",
.owner = THIS_MODULE,
.pm = &navpoint_pm_ops,
},
};
module_platform_driver(navpoint_driver);
MODULE_AUTHOR("Paul Parsons <lost.distance@yahoo.com>");
MODULE_DESCRIPTION("Synaptics NavPoint (PXA27x SSP/SPI) driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:navpoint");

View File

@ -41,7 +41,7 @@
#define GET_ABS_Y(packet) ((packet[2] << 2) | (packet[3] & 0x03))
/** Driver version. */
static const char fsp_drv_ver[] = "1.0.0-K";
static const char fsp_drv_ver[] = "1.1.0-K";
/*
* Make sure that the value being sent to FSP will not conflict with
@ -303,6 +303,27 @@ static int fsp_get_revision(struct psmouse *psmouse, int *rev)
return 0;
}
static int fsp_get_sn(struct psmouse *psmouse, int *sn)
{
int v0, v1, v2;
int rc = -EIO;
/* production number since Cx is available at: 0x0b40 ~ 0x0b42 */
if (fsp_page_reg_write(psmouse, FSP_PAGE_0B))
goto out;
if (fsp_reg_read(psmouse, FSP_REG_SN0, &v0))
goto out;
if (fsp_reg_read(psmouse, FSP_REG_SN1, &v1))
goto out;
if (fsp_reg_read(psmouse, FSP_REG_SN2, &v2))
goto out;
*sn = (v0 << 16) | (v1 << 8) | v2;
rc = 0;
out:
fsp_page_reg_write(psmouse, FSP_PAGE_DEFAULT);
return rc;
}
static int fsp_get_buttons(struct psmouse *psmouse, int *btn)
{
static const int buttons[] = {
@ -1000,16 +1021,21 @@ static int fsp_reconnect(struct psmouse *psmouse)
int fsp_init(struct psmouse *psmouse)
{
struct fsp_data *priv;
int ver, rev;
int ver, rev, sn = 0;
int error;
if (fsp_get_version(psmouse, &ver) ||
fsp_get_revision(psmouse, &rev)) {
return -ENODEV;
}
if (ver >= FSP_VER_STL3888_C0) {
/* firmware information is only available since C0 */
fsp_get_sn(psmouse, &sn);
}
psmouse_info(psmouse, "Finger Sensing Pad, hw: %d.%d.%d, sw: %s\n",
ver >> 4, ver & 0x0F, rev, fsp_drv_ver);
psmouse_info(psmouse,
"Finger Sensing Pad, hw: %d.%d.%d, sn: %x, sw: %s\n",
ver >> 4, ver & 0x0F, rev, sn, fsp_drv_ver);
psmouse->private = priv = kzalloc(sizeof(struct fsp_data), GFP_KERNEL);
if (!priv)

View File

@ -65,6 +65,14 @@
#define FSP_BIT_SWC1_GST_GRP1 BIT(6)
#define FSP_BIT_SWC1_BX_COMPAT BIT(7)
#define FSP_PAGE_0B (0x0b)
#define FSP_PAGE_82 (0x82)
#define FSP_PAGE_DEFAULT FSP_PAGE_82
#define FSP_REG_SN0 (0x40)
#define FSP_REG_SN1 (0x41)
#define FSP_REG_SN2 (0x42)
/* Finger-sensing Pad packet formating related definitions */
/* absolute packet type */

View File

@ -355,15 +355,4 @@ static struct serio_driver sermouse_drv = {
.disconnect = sermouse_disconnect,
};
static int __init sermouse_init(void)
{
return serio_register_driver(&sermouse_drv);
}
static void __exit sermouse_exit(void)
{
serio_unregister_driver(&sermouse_drv);
}
module_init(sermouse_init);
module_exit(sermouse_exit);
module_serio_driver(sermouse_drv);

View File

@ -45,16 +45,6 @@
#define YMIN_NOMINAL 1408
#define YMAX_NOMINAL 4448
/*
* Synaptics touchpads report the y coordinate from bottom to top, which is
* opposite from what userspace expects.
* This function is used to invert y before reporting.
*/
static int synaptics_invert_y(int y)
{
return YMAX_NOMINAL + YMIN_NOMINAL - y;
}
/*****************************************************************************
* Stuff we need even when we do not want native Synaptics support
@ -111,6 +101,16 @@ void synaptics_reset(struct psmouse *psmouse)
* Synaptics communications functions
****************************************************************************/
/*
* Synaptics touchpads report the y coordinate from bottom to top, which is
* opposite from what userspace expects.
* This function is used to invert y before reporting.
*/
static int synaptics_invert_y(int y)
{
return YMAX_NOMINAL + YMIN_NOMINAL - y;
}
/*
* Send a command to the synpatics touchpad by special commands
*/

View File

@ -548,16 +548,4 @@ static struct serio_driver vsxxxaa_drv = {
.disconnect = vsxxxaa_disconnect,
};
static int __init vsxxxaa_init(void)
{
return serio_register_driver(&vsxxxaa_drv);
}
static void __exit vsxxxaa_exit(void)
{
serio_unregister_driver(&vsxxxaa_drv);
}
module_init(vsxxxaa_init);
module_exit(vsxxxaa_exit);
module_serio_driver(vsxxxaa_drv);

View File

@ -1,87 +0,0 @@
/*
* Helpers for open firmware matrix keyboard bindings
*
* Copyright (C) 2012 Google, Inc
*
* Author:
* Olof Johansson <olof@lixom.net>
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/input.h>
#include <linux/of.h>
#include <linux/input/matrix_keypad.h>
#include <linux/export.h>
#include <linux/gfp.h>
#include <linux/slab.h>
struct matrix_keymap_data *
matrix_keyboard_of_fill_keymap(struct device_node *np,
const char *propname)
{
struct matrix_keymap_data *kd;
u32 *keymap;
int proplen, i;
const __be32 *prop;
if (!np)
return NULL;
if (!propname)
propname = "linux,keymap";
prop = of_get_property(np, propname, &proplen);
if (!prop)
return NULL;
if (proplen % sizeof(u32)) {
pr_warn("Malformed keymap property %s in %s\n",
propname, np->full_name);
return NULL;
}
kd = kzalloc(sizeof(*kd), GFP_KERNEL);
if (!kd)
return NULL;
kd->keymap = keymap = kzalloc(proplen, GFP_KERNEL);
if (!kd->keymap) {
kfree(kd);
return NULL;
}
kd->keymap_size = proplen / sizeof(u32);
for (i = 0; i < kd->keymap_size; i++) {
u32 tmp = be32_to_cpup(prop + i);
int key_code, row, col;
row = (tmp >> 24) & 0xff;
col = (tmp >> 16) & 0xff;
key_code = tmp & 0xffff;
keymap[i] = KEY(row, col, key_code);
}
return kd;
}
EXPORT_SYMBOL_GPL(matrix_keyboard_of_fill_keymap);
void matrix_keyboard_of_free_keymap(const struct matrix_keymap_data *kd)
{
if (kd) {
kfree(kd->keymap);
kfree(kd);
}
}
EXPORT_SYMBOL_GPL(matrix_keyboard_of_free_keymap);

View File

@ -206,6 +206,7 @@ static const struct pci_device_id pcips2_ids[] = {
},
{ 0, }
};
MODULE_DEVICE_TABLE(pci, pcips2_ids);
static struct pci_driver pcips2_driver = {
.name = "pcips2",
@ -214,20 +215,8 @@ static struct pci_driver pcips2_driver = {
.remove = __devexit_p(pcips2_remove),
};
static int __init pcips2_init(void)
{
return pci_register_driver(&pcips2_driver);
}
static void __exit pcips2_exit(void)
{
pci_unregister_driver(&pcips2_driver);
}
module_init(pcips2_init);
module_exit(pcips2_exit);
module_pci_driver(pcips2_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
MODULE_DESCRIPTION("PCI PS/2 keyboard/mouse driver");
MODULE_DEVICE_TABLE(pci, pcips2_ids);

View File

@ -304,15 +304,4 @@ static struct serio_driver ps2mult_drv = {
.reconnect = ps2mult_reconnect,
};
static int __init ps2mult_init(void)
{
return serio_register_driver(&ps2mult_drv);
}
static void __exit ps2mult_exit(void)
{
serio_unregister_driver(&ps2mult_drv);
}
module_init(ps2mult_init);
module_exit(ps2mult_exit);
module_serio_driver(ps2mult_drv);

View File

@ -165,31 +165,38 @@ static ssize_t serio_raw_read(struct file *file, char __user *buffer,
struct serio_raw *serio_raw = client->serio_raw;
char uninitialized_var(c);
ssize_t read = 0;
int retval;
int error;
if (serio_raw->dead)
return -ENODEV;
for (;;) {
if (serio_raw->dead)
return -ENODEV;
if (serio_raw->head == serio_raw->tail && (file->f_flags & O_NONBLOCK))
return -EAGAIN;
if (serio_raw->head == serio_raw->tail &&
(file->f_flags & O_NONBLOCK))
return -EAGAIN;
retval = wait_event_interruptible(serio_raw->wait,
serio_raw->head != serio_raw->tail || serio_raw->dead);
if (retval)
return retval;
if (serio_raw->dead)
return -ENODEV;
while (read < count && serio_raw_fetch_byte(serio_raw, &c)) {
if (put_user(c, buffer++)) {
retval = -EFAULT;
if (count == 0)
break;
while (read < count && serio_raw_fetch_byte(serio_raw, &c)) {
if (put_user(c, buffer++))
return -EFAULT;
read++;
}
if (read)
break;
if (!(file->f_flags & O_NONBLOCK)) {
error = wait_event_interruptible(serio_raw->wait,
serio_raw->head != serio_raw->tail ||
serio_raw->dead);
if (error)
return error;
}
read++;
}
return read ?: retval;
return read;
}
static ssize_t serio_raw_write(struct file *file, const char __user *buffer,
@ -197,8 +204,7 @@ static ssize_t serio_raw_write(struct file *file, const char __user *buffer,
{
struct serio_raw_client *client = file->private_data;
struct serio_raw *serio_raw = client->serio_raw;
ssize_t written = 0;
int retval;
int retval = 0;
unsigned char c;
retval = mutex_lock_interruptible(&serio_raw_mutex);
@ -218,16 +224,20 @@ static ssize_t serio_raw_write(struct file *file, const char __user *buffer,
retval = -EFAULT;
goto out;
}
if (serio_write(serio_raw->serio, c)) {
retval = -EIO;
/* Either signal error or partial write */
if (retval == 0)
retval = -EIO;
goto out;
}
written++;
retval++;
}
out:
mutex_unlock(&serio_raw_mutex);
return written ?: retval;
return retval;
}
static unsigned int serio_raw_poll(struct file *file, poll_table *wait)
@ -432,15 +442,4 @@ static struct serio_driver serio_raw_drv = {
.manual_bind = true,
};
static int __init serio_raw_init(void)
{
return serio_register_driver(&serio_raw_drv);
}
static void __exit serio_raw_exit(void)
{
serio_unregister_driver(&serio_raw_drv);
}
module_init(serio_raw_init);
module_exit(serio_raw_exit);
module_serio_driver(serio_raw_drv);

View File

@ -73,7 +73,8 @@ struct xps2data {
spinlock_t lock;
void __iomem *base_address; /* virt. address of control registers */
unsigned int flags;
struct serio serio; /* serio */
struct serio *serio; /* serio */
struct device *dev;
};
/************************************/
@ -119,7 +120,7 @@ static irqreturn_t xps2_interrupt(int irq, void *dev_id)
/* Check which interrupt is active */
if (intr_sr & XPS2_IPIXR_RX_OVF)
dev_warn(drvdata->serio.dev.parent, "receive overrun error\n");
dev_warn(drvdata->dev, "receive overrun error\n");
if (intr_sr & XPS2_IPIXR_RX_ERR)
drvdata->flags |= SERIO_PARITY;
@ -132,10 +133,10 @@ static irqreturn_t xps2_interrupt(int irq, void *dev_id)
/* Error, if a byte is not received */
if (status) {
dev_err(drvdata->serio.dev.parent,
dev_err(drvdata->dev,
"wrong rcvd byte count (%d)\n", status);
} else {
serio_interrupt(&drvdata->serio, c, drvdata->flags);
serio_interrupt(drvdata->serio, c, drvdata->flags);
drvdata->flags = 0;
}
}
@ -193,7 +194,7 @@ static int sxps2_open(struct serio *pserio)
error = request_irq(drvdata->irq, &xps2_interrupt, 0,
DRIVER_NAME, drvdata);
if (error) {
dev_err(drvdata->serio.dev.parent,
dev_err(drvdata->dev,
"Couldn't allocate interrupt %d\n", drvdata->irq);
return error;
}
@ -259,15 +260,16 @@ static int __devinit xps2_of_probe(struct platform_device *ofdev)
}
drvdata = kzalloc(sizeof(struct xps2data), GFP_KERNEL);
if (!drvdata) {
dev_err(dev, "Couldn't allocate device private record\n");
return -ENOMEM;
serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
if (!drvdata || !serio) {
error = -ENOMEM;
goto failed1;
}
dev_set_drvdata(dev, drvdata);
spin_lock_init(&drvdata->lock);
drvdata->irq = r_irq.start;
drvdata->serio = serio;
drvdata->dev = dev;
phys_addr = r_mem.start;
remap_size = resource_size(&r_mem);
@ -298,7 +300,6 @@ static int __devinit xps2_of_probe(struct platform_device *ofdev)
(unsigned long long)phys_addr, drvdata->base_address,
drvdata->irq);
serio = &drvdata->serio;
serio->id.type = SERIO_8042;
serio->write = sxps2_write;
serio->open = sxps2_open;
@ -312,13 +313,14 @@ static int __devinit xps2_of_probe(struct platform_device *ofdev)
serio_register_port(serio);
platform_set_drvdata(ofdev, drvdata);
return 0; /* success */
failed2:
release_mem_region(phys_addr, remap_size);
failed1:
kfree(serio);
kfree(drvdata);
dev_set_drvdata(dev, NULL);
return error;
}
@ -333,22 +335,21 @@ failed1:
*/
static int __devexit xps2_of_remove(struct platform_device *of_dev)
{
struct device *dev = &of_dev->dev;
struct xps2data *drvdata = dev_get_drvdata(dev);
struct xps2data *drvdata = platform_get_drvdata(of_dev);
struct resource r_mem; /* IO mem resources */
serio_unregister_port(&drvdata->serio);
serio_unregister_port(drvdata->serio);
iounmap(drvdata->base_address);
/* Get iospace of the device */
if (of_address_to_resource(of_dev->dev.of_node, 0, &r_mem))
dev_err(dev, "invalid address\n");
dev_err(drvdata->dev, "invalid address\n");
else
release_mem_region(r_mem.start, resource_size(&r_mem));
kfree(drvdata);
dev_set_drvdata(dev, NULL);
platform_set_drvdata(of_dev, NULL);
return 0;
}

View File

@ -1862,7 +1862,7 @@ aiptek_probe(struct usb_interface *intf, const struct usb_device_id *id)
if (i == ARRAY_SIZE(speeds)) {
dev_info(&intf->dev,
"Aiptek tried all speeds, no sane response\n");
goto fail2;
goto fail3;
}
/* Associate this driver's struct with the usb interface.

View File

@ -135,6 +135,6 @@ extern const struct usb_device_id wacom_ids[];
void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len);
void wacom_setup_device_quirks(struct wacom_features *features);
void wacom_setup_input_capabilities(struct input_dev *input_dev,
struct wacom_wac *wacom_wac);
int wacom_setup_input_capabilities(struct input_dev *input_dev,
struct wacom_wac *wacom_wac);
#endif

View File

@ -28,6 +28,7 @@
#define HID_USAGE_Y_TILT 0x3e
#define HID_USAGE_FINGER 0x22
#define HID_USAGE_STYLUS 0x20
#define HID_USAGE_CONTACTMAX 0x55
#define HID_COLLECTION 0xa1
#define HID_COLLECTION_LOGICAL 0x02
#define HID_COLLECTION_END 0xc0
@ -204,6 +205,27 @@ static int wacom_parse_logical_collection(unsigned char *report,
return length;
}
static void wacom_retrieve_report_data(struct usb_interface *intf,
struct wacom_features *features)
{
int result = 0;
unsigned char *rep_data;
rep_data = kmalloc(2, GFP_KERNEL);
if (rep_data) {
rep_data[0] = 12;
result = wacom_get_report(intf, WAC_HID_FEATURE_REPORT,
rep_data[0], &rep_data, 2,
WAC_MSG_RETRIES);
if (result >= 0 && rep_data[1] > 2)
features->touch_max = rep_data[1];
kfree(rep_data);
}
}
/*
* Interface Descriptor of wacom devices can be incomplete and
* inconsistent so wacom_features table is used to store stylus
@ -236,6 +258,9 @@ static int wacom_parse_logical_collection(unsigned char *report,
* 3rd gen Bamboo Touch no longer define a Digitizer-Finger Pysical
* Collection. Instead they define a Logical Collection with a single
* Logical Maximum for both X and Y.
*
* Intuos5 touch interface does not contain useful data. We deal with
* this after returning from this function.
*/
static int wacom_parse_hid(struct usb_interface *intf,
struct hid_descriptor *hid_desc,
@ -295,6 +320,10 @@ static int wacom_parse_hid(struct usb_interface *intf,
/* need to reset back */
features->pktlen = WACOM_PKGLEN_TPC2FG;
}
if (features->type == MTSCREEN)
features->pktlen = WACOM_PKGLEN_MTOUCH;
if (features->type == BAMBOO_PT) {
/* need to reset back */
features->pktlen = WACOM_PKGLEN_BBTOUCH;
@ -327,18 +356,15 @@ static int wacom_parse_hid(struct usb_interface *intf,
case HID_USAGE_Y:
if (usage == WCM_DESKTOP) {
if (finger) {
features->device_type = BTN_TOOL_FINGER;
if (features->type == TABLETPC2FG) {
/* need to reset back */
features->pktlen = WACOM_PKGLEN_TPC2FG;
int type = features->type;
if (type == TABLETPC2FG || type == MTSCREEN) {
features->y_max =
get_unaligned_le16(&report[i + 3]);
features->y_phy =
get_unaligned_le16(&report[i + 6]);
i += 7;
} else if (features->type == BAMBOO_PT) {
/* need to reset back */
features->pktlen = WACOM_PKGLEN_BBTOUCH;
} else if (type == BAMBOO_PT) {
features->y_phy =
get_unaligned_le16(&report[i + 3]);
features->y_max =
@ -352,10 +378,6 @@ static int wacom_parse_hid(struct usb_interface *intf,
i += 4;
}
} else if (pen) {
/* penabled only accepts exact bytes of data */
if (features->type == TABLETPC2FG)
features->pktlen = WACOM_PKGLEN_GRAPHIRE;
features->device_type = BTN_TOOL_PEN;
features->y_max =
get_unaligned_le16(&report[i + 3]);
i += 4;
@ -377,6 +399,11 @@ static int wacom_parse_hid(struct usb_interface *intf,
pen = 1;
i++;
break;
case HID_USAGE_CONTACTMAX:
wacom_retrieve_report_data(intf, features);
i++;
break;
}
break;
@ -413,22 +440,29 @@ static int wacom_query_tablet_data(struct usb_interface *intf, struct wacom_feat
if (!rep_data)
return error;
/* ask to report tablet data if it is MT Tablet PC or
* not a Tablet PC */
if (features->type == TABLETPC2FG) {
do {
rep_data[0] = 3;
rep_data[1] = 4;
rep_data[2] = 0;
rep_data[3] = 0;
report_id = 3;
error = wacom_set_report(intf, WAC_HID_FEATURE_REPORT,
report_id, rep_data, 4, 1);
if (error >= 0)
error = wacom_get_report(intf,
WAC_HID_FEATURE_REPORT,
report_id, rep_data, 4, 1);
} while ((error < 0 || rep_data[1] != 4) && limit++ < WAC_MSG_RETRIES);
/* ask to report Wacom data */
if (features->device_type == BTN_TOOL_FINGER) {
/* if it is an MT Tablet PC touch */
if (features->type == TABLETPC2FG ||
features->type == MTSCREEN) {
do {
rep_data[0] = 3;
rep_data[1] = 4;
rep_data[2] = 0;
rep_data[3] = 0;
report_id = 3;
error = wacom_set_report(intf,
WAC_HID_FEATURE_REPORT,
report_id,
rep_data, 4, 1);
if (error >= 0)
error = wacom_get_report(intf,
WAC_HID_FEATURE_REPORT,
report_id,
rep_data, 4, 1);
} while ((error < 0 || rep_data[1] != 4) &&
limit++ < WAC_MSG_RETRIES);
}
} else if (features->type != TABLETPC &&
features->type != WIRELESS &&
features->device_type == BTN_TOOL_PEN) {
@ -450,7 +484,7 @@ static int wacom_query_tablet_data(struct usb_interface *intf, struct wacom_feat
}
static int wacom_retrieve_hid_descriptor(struct usb_interface *intf,
struct wacom_features *features)
struct wacom_features *features)
{
int error = 0;
struct usb_host_interface *interface = intf->cur_altsetting;
@ -478,16 +512,21 @@ static int wacom_retrieve_hid_descriptor(struct usb_interface *intf,
}
}
/* only Tablet PCs and Bamboo P&T need to retrieve the info */
if ((features->type != TABLETPC) && (features->type != TABLETPC2FG) &&
(features->type != BAMBOO_PT))
/* only devices that support touch need to retrieve the info */
if (features->type != TABLETPC &&
features->type != TABLETPC2FG &&
features->type != BAMBOO_PT &&
features->type != MTSCREEN) {
goto out;
}
if (usb_get_extra_descriptor(interface, HID_DEVICET_HID, &hid_desc)) {
if (usb_get_extra_descriptor(&interface->endpoint[0],
HID_DEVICET_REPORT, &hid_desc)) {
printk("wacom: can not retrieve extra class descriptor\n");
error = 1;
error = usb_get_extra_descriptor(interface, HID_DEVICET_HID, &hid_desc);
if (error) {
error = usb_get_extra_descriptor(&interface->endpoint[0],
HID_DEVICET_REPORT, &hid_desc);
if (error) {
dev_err(&intf->dev,
"can not retrieve extra class descriptor\n");
goto out;
}
}
@ -577,23 +616,39 @@ static void wacom_remove_shared_data(struct wacom_wac *wacom)
static int wacom_led_control(struct wacom *wacom)
{
unsigned char *buf;
int retval, led = 0;
int retval;
buf = kzalloc(9, GFP_KERNEL);
if (!buf)
return -ENOMEM;
if (wacom->wacom_wac.features.type == WACOM_21UX2 ||
wacom->wacom_wac.features.type == WACOM_24HD)
led = (wacom->led.select[1] << 4) | 0x40;
if (wacom->wacom_wac.features.type >= INTUOS5S &&
wacom->wacom_wac.features.type <= INTUOS5L) {
/*
* Touch Ring and crop mark LED luminance may take on
* one of four values:
* 0 = Low; 1 = Medium; 2 = High; 3 = Off
*/
int ring_led = wacom->led.select[0] & 0x03;
int ring_lum = (((wacom->led.llv & 0x60) >> 5) - 1) & 0x03;
int crop_lum = 0;
led |= wacom->led.select[0] | 0x4;
buf[0] = WAC_CMD_LED_CONTROL;
buf[1] = (crop_lum << 4) | (ring_lum << 2) | (ring_led);
}
else {
int led = wacom->led.select[0] | 0x4;
buf[0] = WAC_CMD_LED_CONTROL;
buf[1] = led;
buf[2] = wacom->led.llv;
buf[3] = wacom->led.hlv;
buf[4] = wacom->led.img_lum;
if (wacom->wacom_wac.features.type == WACOM_21UX2 ||
wacom->wacom_wac.features.type == WACOM_24HD)
led |= (wacom->led.select[1] << 4) | 0x40;
buf[0] = WAC_CMD_LED_CONTROL;
buf[1] = led;
buf[2] = wacom->led.llv;
buf[3] = wacom->led.hlv;
buf[4] = wacom->led.img_lum;
}
retval = wacom_set_report(wacom->intf, 0x03, WAC_CMD_LED_CONTROL,
buf, 9, WAC_CMD_RETRIES);
@ -786,6 +841,17 @@ static struct attribute_group intuos4_led_attr_group = {
.attrs = intuos4_led_attrs,
};
static struct attribute *intuos5_led_attrs[] = {
&dev_attr_status0_luminance.attr,
&dev_attr_status_led0_select.attr,
NULL
};
static struct attribute_group intuos5_led_attr_group = {
.name = "wacom_led",
.attrs = intuos5_led_attrs,
};
static int wacom_initialize_leds(struct wacom *wacom)
{
int error;
@ -815,6 +881,19 @@ static int wacom_initialize_leds(struct wacom *wacom)
&cintiq_led_attr_group);
break;
case INTUOS5S:
case INTUOS5:
case INTUOS5L:
wacom->led.select[0] = 0;
wacom->led.select[1] = 0;
wacom->led.llv = 32;
wacom->led.hlv = 0;
wacom->led.img_lum = 0;
error = sysfs_create_group(&wacom->intf->dev.kobj,
&intuos5_led_attr_group);
break;
default:
return 0;
}
@ -843,6 +922,13 @@ static void wacom_destroy_leds(struct wacom *wacom)
sysfs_remove_group(&wacom->intf->dev.kobj,
&cintiq_led_attr_group);
break;
case INTUOS5S:
case INTUOS5:
case INTUOS5L:
sysfs_remove_group(&wacom->intf->dev.kobj,
&intuos5_led_attr_group);
break;
}
}
@ -904,8 +990,10 @@ static int wacom_register_input(struct wacom *wacom)
int error;
input_dev = input_allocate_device();
if (!input_dev)
return -ENOMEM;
if (!input_dev) {
error = -ENOMEM;
goto fail1;
}
input_dev->name = wacom_wac->name;
input_dev->dev.parent = &intf->dev;
@ -915,14 +1003,20 @@ static int wacom_register_input(struct wacom *wacom)
input_set_drvdata(input_dev, wacom);
wacom_wac->input = input_dev;
wacom_setup_input_capabilities(input_dev, wacom_wac);
error = wacom_setup_input_capabilities(input_dev, wacom_wac);
if (error)
goto fail1;
error = input_register_device(input_dev);
if (error) {
input_free_device(input_dev);
wacom_wac->input = NULL;
}
if (error)
goto fail2;
return 0;
fail2:
input_free_device(input_dev);
wacom_wac->input = NULL;
fail1:
return error;
}
@ -941,22 +1035,22 @@ static void wacom_wireless_work(struct work_struct *work)
wacom = usb_get_intfdata(usbdev->config->interface[1]);
if (wacom->wacom_wac.input)
input_unregister_device(wacom->wacom_wac.input);
wacom->wacom_wac.input = 0;
wacom->wacom_wac.input = NULL;
/* Touch interface */
wacom = usb_get_intfdata(usbdev->config->interface[2]);
if (wacom->wacom_wac.input)
input_unregister_device(wacom->wacom_wac.input);
wacom->wacom_wac.input = 0;
wacom->wacom_wac.input = NULL;
if (wacom_wac->pid == 0) {
printk(KERN_INFO "wacom: wireless tablet disconnected\n");
dev_info(&wacom->intf->dev, "wireless tablet disconnected\n");
} else {
const struct usb_device_id *id = wacom_ids;
printk(KERN_INFO
"wacom: wireless tablet connected with PID %x\n",
wacom_wac->pid);
dev_info(&wacom->intf->dev,
"wireless tablet connected with PID %x\n",
wacom_wac->pid);
while (id->match_flags) {
if (id->idVendor == USB_VENDOR_ID_WACOM &&
@ -966,8 +1060,8 @@ static void wacom_wireless_work(struct work_struct *work)
}
if (!id->match_flags) {
printk(KERN_INFO
"wacom: ignorning unknown PID.\n");
dev_info(&wacom->intf->dev,
"ignoring unknown PID.\n");
return;
}
@ -1038,11 +1132,33 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
endpoint = &intf->cur_altsetting->endpoint[0].desc;
/* Retrieve the physical and logical size for OEM devices */
/* Retrieve the physical and logical size for touch devices */
error = wacom_retrieve_hid_descriptor(intf, features);
if (error)
goto fail3;
/*
* Intuos5 has no useful data about its touch interface in its
* HID descriptor. If this is the touch interface (wMaxPacketSize
* of WACOM_PKGLEN_BBTOUCH3), override the table values.
*/
if (features->type >= INTUOS5S && features->type <= INTUOS5L) {
if (endpoint->wMaxPacketSize == WACOM_PKGLEN_BBTOUCH3) {
features->device_type = BTN_TOOL_FINGER;
features->pktlen = WACOM_PKGLEN_BBTOUCH3;
features->x_phy =
(features->x_max * 100) / features->x_resolution;
features->y_phy =
(features->y_max * 100) / features->y_resolution;
features->x_max = 4096;
features->y_max = 4096;
} else {
features->device_type = BTN_TOOL_PEN;
}
}
wacom_setup_device_quirks(features);
strlcpy(wacom_wac->name, features->name, sizeof(wacom_wac->name));

View File

@ -61,7 +61,8 @@ static int wacom_penpartner_irq(struct wacom_wac *wacom)
break;
default:
printk(KERN_INFO "wacom_penpartner_irq: received unknown report #%d\n", data[0]);
dev_dbg(input->dev.parent,
"%s: received unknown report #%d\n", __func__, data[0]);
return 0;
}
@ -76,8 +77,8 @@ static int wacom_pl_irq(struct wacom_wac *wacom)
int prox, pressure;
if (data[0] != WACOM_REPORT_PENABLED) {
dev_dbg(&input->dev,
"wacom_pl_irq: received unknown report #%d\n", data[0]);
dev_dbg(input->dev.parent,
"%s: received unknown report #%d\n", __func__, data[0]);
return 0;
}
@ -147,7 +148,8 @@ static int wacom_ptu_irq(struct wacom_wac *wacom)
struct input_dev *input = wacom->input;
if (data[0] != WACOM_REPORT_PENABLED) {
printk(KERN_INFO "wacom_ptu_irq: received unknown report #%d\n", data[0]);
dev_dbg(input->dev.parent,
"%s: received unknown report #%d\n", __func__, data[0]);
return 0;
}
@ -176,7 +178,8 @@ static int wacom_dtu_irq(struct wacom_wac *wacom)
struct input_dev *input = wacom->input;
int prox = data[1] & 0x20, pressure;
dev_dbg(&input->dev, "wacom_dtu_irq: received report #%d\n", data[0]);
dev_dbg(input->dev.parent,
"%s: received report #%d", __func__, data[0]);
if (prox) {
/* Going into proximity select tool */
@ -212,9 +215,8 @@ static int wacom_graphire_irq(struct wacom_wac *wacom)
int retval = 0;
if (data[0] != WACOM_REPORT_PENABLED) {
dev_dbg(&input->dev,
"wacom_graphire_irq: received unknown report #%d\n",
data[0]);
dev_dbg(input->dev.parent,
"%s: received unknown report #%d\n", __func__, data[0]);
goto exit;
}
@ -324,6 +326,9 @@ static int wacom_intuos_inout(struct wacom_wac *wacom)
/* Enter report */
if ((data[1] & 0xfc) == 0xc0) {
if (features->type >= INTUOS5S && features->type <= INTUOS5L)
wacom->shared->stylus_in_proximity = true;
/* serial number of the tool */
wacom->serial[idx] = ((data[3] & 0x0f) << 28) +
(data[4] << 20) + (data[5] << 12) +
@ -409,6 +414,9 @@ static int wacom_intuos_inout(struct wacom_wac *wacom)
/* Exit report */
if ((data[1] & 0xfe) == 0x80) {
if (features->type >= INTUOS5S && features->type <= INTUOS5L)
wacom->shared->stylus_in_proximity = false;
/*
* Reset all states otherwise we lose the initial states
* when in-prox next time
@ -455,6 +463,7 @@ static void wacom_intuos_general(struct wacom_wac *wacom)
if ((data[1] & 0xb8) == 0xa0) {
t = (data[6] << 2) | ((data[7] >> 6) & 3);
if ((features->type >= INTUOS4S && features->type <= INTUOS4L) ||
(features->type >= INTUOS5S && features->type <= INTUOS5L) ||
features->type == WACOM_21UX2 || features->type == WACOM_24HD) {
t = (t << 1) | (data[1] & 1);
}
@ -485,11 +494,13 @@ static int wacom_intuos_irq(struct wacom_wac *wacom)
unsigned int t;
int idx = 0, result;
if (data[0] != WACOM_REPORT_PENABLED && data[0] != WACOM_REPORT_INTUOSREAD
&& data[0] != WACOM_REPORT_INTUOSWRITE && data[0] != WACOM_REPORT_INTUOSPAD) {
dev_dbg(&input->dev,
"wacom_intuos_irq: received unknown report #%d\n",
data[0]);
if (data[0] != WACOM_REPORT_PENABLED &&
data[0] != WACOM_REPORT_INTUOSREAD &&
data[0] != WACOM_REPORT_INTUOSWRITE &&
data[0] != WACOM_REPORT_INTUOSPAD &&
data[0] != WACOM_REPORT_INTUOS5PAD) {
dev_dbg(input->dev.parent,
"%s: received unknown report #%d\n", __func__, data[0]);
return 0;
}
@ -498,7 +509,7 @@ static int wacom_intuos_irq(struct wacom_wac *wacom)
idx = data[1] & 0x01;
/* pad packets. Works as a second tool and is always in prox */
if (data[0] == WACOM_REPORT_INTUOSPAD) {
if (data[0] == WACOM_REPORT_INTUOSPAD || data[0] == WACOM_REPORT_INTUOS5PAD) {
if (features->type >= INTUOS4S && features->type <= INTUOS4L) {
input_report_key(input, BTN_0, (data[2] & 0x01));
input_report_key(input, BTN_1, (data[3] & 0x01));
@ -574,6 +585,34 @@ static int wacom_intuos_irq(struct wacom_wac *wacom)
input_report_key(input, wacom->tool[1], 0);
input_report_abs(input, ABS_MISC, 0);
}
} else if (features->type >= INTUOS5S && features->type <= INTUOS5L) {
int i;
/* Touch ring mode switch has no capacitive sensor */
input_report_key(input, BTN_0, (data[3] & 0x01));
/*
* ExpressKeys on Intuos5 have a capacitive sensor in
* addition to the mechanical switch. Switch data is
* stored in data[4], capacitive data in data[5].
*/
for (i = 0; i < 8; i++)
input_report_key(input, BTN_1 + i, data[4] & (1 << i));
if (data[2] & 0x80) {
input_report_abs(input, ABS_WHEEL, (data[2] & 0x7f));
} else {
/* Out of proximity, clear wheel value. */
input_report_abs(input, ABS_WHEEL, 0);
}
if (data[2] | (data[3] & 0x01) | data[4]) {
input_report_key(input, wacom->tool[1], 1);
input_report_abs(input, ABS_MISC, PAD_DEVICE_ID);
} else {
input_report_key(input, wacom->tool[1], 0);
input_report_abs(input, ABS_MISC, 0);
}
} else {
if (features->type == WACOM_21UX2) {
input_report_key(input, BTN_0, (data[5] & 0x01));
@ -637,7 +676,9 @@ static int wacom_intuos_irq(struct wacom_wac *wacom)
(features->type == INTUOS3 ||
features->type == INTUOS3S ||
features->type == INTUOS4 ||
features->type == INTUOS4S)) {
features->type == INTUOS4S ||
features->type == INTUOS5 ||
features->type == INTUOS5S)) {
return 0;
}
@ -690,7 +731,8 @@ static int wacom_intuos_irq(struct wacom_wac *wacom)
} else if (wacom->tool[idx] == BTN_TOOL_MOUSE) {
/* I4 mouse */
if (features->type >= INTUOS4S && features->type <= INTUOS4L) {
if ((features->type >= INTUOS4S && features->type <= INTUOS4L) ||
(features->type >= INTUOS5S && features->type <= INTUOS5L)) {
input_report_key(input, BTN_LEFT, data[6] & 0x01);
input_report_key(input, BTN_MIDDLE, data[6] & 0x02);
input_report_key(input, BTN_RIGHT, data[6] & 0x04);
@ -717,7 +759,7 @@ static int wacom_intuos_irq(struct wacom_wac *wacom)
}
}
} else if ((features->type < INTUOS3S || features->type == INTUOS3L ||
features->type == INTUOS4L) &&
features->type == INTUOS4L || features->type == INTUOS5L) &&
wacom->tool[idx] == BTN_TOOL_LENS) {
/* Lens cursor packets */
input_report_key(input, BTN_LEFT, data[8] & 0x01);
@ -734,6 +776,72 @@ static int wacom_intuos_irq(struct wacom_wac *wacom)
return 1;
}
static int find_slot_from_contactid(struct wacom_wac *wacom, int contactid)
{
int touch_max = wacom->features.touch_max;
int i;
if (!wacom->slots)
return -1;
for (i = 0; i < touch_max; ++i) {
if (wacom->slots[i] == contactid)
return i;
}
for (i = 0; i < touch_max; ++i) {
if (wacom->slots[i] == -1)
return i;
}
return -1;
}
static int wacom_mt_touch(struct wacom_wac *wacom)
{
struct input_dev *input = wacom->input;
char *data = wacom->data;
int i;
int current_num_contacts = data[2];
int contacts_to_send = 0;
/*
* First packet resets the counter since only the first
* packet in series will have non-zero current_num_contacts.
*/
if (current_num_contacts)
wacom->num_contacts_left = current_num_contacts;
/* There are at most 5 contacts per packet */
contacts_to_send = min(5, wacom->num_contacts_left);
for (i = 0; i < contacts_to_send; i++) {
int offset = (WACOM_BYTES_PER_MT_PACKET * i) + 3;
bool touch = data[offset] & 0x1;
int id = le16_to_cpup((__le16 *)&data[offset + 1]);
int slot = find_slot_from_contactid(wacom, id);
if (slot < 0)
continue;
input_mt_slot(input, slot);
input_mt_report_slot_state(input, MT_TOOL_FINGER, touch);
if (touch) {
int x = le16_to_cpup((__le16 *)&data[offset + 7]);
int y = le16_to_cpup((__le16 *)&data[offset + 9]);
input_report_abs(input, ABS_MT_POSITION_X, x);
input_report_abs(input, ABS_MT_POSITION_Y, y);
}
wacom->slots[slot] = touch ? id : -1;
}
input_mt_report_pointer_emulation(input, true);
wacom->num_contacts_left -= contacts_to_send;
if (wacom->num_contacts_left < 0)
wacom->num_contacts_left = 0;
return 1;
}
static int wacom_tpc_mt_touch(struct wacom_wac *wacom)
{
struct input_dev *input = wacom->input;
@ -772,6 +880,9 @@ static int wacom_tpc_single_touch(struct wacom_wac *wacom, size_t len)
bool prox;
int x = 0, y = 0;
if (wacom->features.touch_max > 1 || len > WACOM_PKGLEN_TPC2FG)
return 0;
if (!wacom->shared->stylus_in_proximity) {
if (len == WACOM_PKGLEN_TPC1FG) {
prox = data[0] & 0x01;
@ -835,15 +946,15 @@ static int wacom_tpc_irq(struct wacom_wac *wacom, size_t len)
{
char *data = wacom->data;
dev_dbg(&wacom->input->dev, "wacom_tpc_irq: received report #%d\n",
data[0]);
dev_dbg(wacom->input->dev.parent,
"%s: received report #%d\n", __func__, data[0]);
switch (len) {
case WACOM_PKGLEN_TPC1FG:
return wacom_tpc_single_touch(wacom, len);
return wacom_tpc_single_touch(wacom, len);
case WACOM_PKGLEN_TPC2FG:
return wacom_tpc_mt_touch(wacom);
return wacom_tpc_mt_touch(wacom);
default:
switch (data[0]) {
@ -852,6 +963,9 @@ static int wacom_tpc_irq(struct wacom_wac *wacom, size_t len)
case WACOM_REPORT_TPCST:
return wacom_tpc_single_touch(wacom, len);
case WACOM_REPORT_TPCMT:
return wacom_mt_touch(wacom);
case WACOM_REPORT_PENABLED:
return wacom_tpc_pen(wacom);
}
@ -1120,8 +1234,18 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len)
sync = wacom_intuos_irq(wacom_wac);
break;
case INTUOS5S:
case INTUOS5:
case INTUOS5L:
if (len == WACOM_PKGLEN_BBTOUCH3)
sync = wacom_bpt3_touch(wacom_wac);
else
sync = wacom_intuos_irq(wacom_wac);
break;
case TABLETPC:
case TABLETPC2FG:
case MTSCREEN:
sync = wacom_tpc_irq(wacom_wac, len);
break;
@ -1194,7 +1318,9 @@ void wacom_setup_device_quirks(struct wacom_features *features)
/* these device have multiple inputs */
if (features->type == TABLETPC || features->type == TABLETPC2FG ||
features->type == BAMBOO_PT || features->type == WIRELESS)
features->type == BAMBOO_PT || features->type == WIRELESS ||
(features->type >= INTUOS5S && features->type <= INTUOS5L) ||
features->type == MTSCREEN)
features->quirks |= WACOM_QUIRK_MULTI_INPUT;
/* quirk for bamboo touch with 2 low res touches */
@ -1225,8 +1351,8 @@ static unsigned int wacom_calculate_touch_res(unsigned int logical_max,
return (logical_max * 100) / physical_max;
}
void wacom_setup_input_capabilities(struct input_dev *input_dev,
struct wacom_wac *wacom_wac)
int wacom_setup_input_capabilities(struct input_dev *input_dev,
struct wacom_wac *wacom_wac)
{
struct wacom_features *features = &wacom_wac->features;
int i;
@ -1361,6 +1487,50 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev,
wacom_setup_intuos(wacom_wac);
break;
case INTUOS5:
case INTUOS5L:
if (features->device_type == BTN_TOOL_PEN) {
__set_bit(BTN_7, input_dev->keybit);
__set_bit(BTN_8, input_dev->keybit);
}
/* fall through */
case INTUOS5S:
__set_bit(INPUT_PROP_POINTER, input_dev->propbit);
if (features->device_type == BTN_TOOL_PEN) {
for (i = 0; i < 7; i++)
__set_bit(BTN_0 + i, input_dev->keybit);
input_set_abs_params(input_dev, ABS_DISTANCE, 0,
features->distance_max,
0, 0);
input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0);
wacom_setup_intuos(wacom_wac);
} else if (features->device_type == BTN_TOOL_FINGER) {
__clear_bit(ABS_MISC, input_dev->absbit);
__set_bit(BTN_TOOL_FINGER, input_dev->keybit);
__set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit);
__set_bit(BTN_TOOL_TRIPLETAP, input_dev->keybit);
__set_bit(BTN_TOOL_QUADTAP, input_dev->keybit);
input_mt_init_slots(input_dev, features->touch_max);
input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR,
0, 255, 0, 0);
input_set_abs_params(input_dev, ABS_MT_POSITION_X,
0, features->x_max,
features->x_fuzz, 0);
input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
0, features->y_max,
features->y_fuzz, 0);
}
break;
case INTUOS4:
case INTUOS4L:
__set_bit(BTN_7, input_dev->keybit);
@ -1378,9 +1548,19 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev,
break;
case TABLETPC2FG:
case MTSCREEN:
if (features->device_type == BTN_TOOL_FINGER) {
input_mt_init_slots(input_dev, 2);
wacom_wac->slots = kmalloc(features->touch_max *
sizeof(int),
GFP_KERNEL);
if (!wacom_wac->slots)
return -ENOMEM;
for (i = 0; i < features->touch_max; i++)
wacom_wac->slots[i] = -1;
input_mt_init_slots(input_dev, features->touch_max);
input_set_abs_params(input_dev, ABS_MT_TOOL_TYPE,
0, MT_TOOL_MAX, 0, 0);
input_set_abs_params(input_dev, ABS_MT_POSITION_X,
@ -1435,6 +1615,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_init_slots(input_dev, features->touch_max);
if (features->pktlen == WACOM_PKGLEN_BBTOUCH3) {
__set_bit(BTN_TOOL_TRIPLETAP,
@ -1442,13 +1623,9 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev,
__set_bit(BTN_TOOL_QUADTAP,
input_dev->keybit);
input_mt_init_slots(input_dev, 16);
input_set_abs_params(input_dev,
ABS_MT_TOUCH_MAJOR,
0, 255, 0, 0);
} else {
input_mt_init_slots(input_dev, 2);
}
input_set_abs_params(input_dev, ABS_MT_POSITION_X,
@ -1468,6 +1645,7 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev,
}
break;
}
return 0;
}
static const struct wacom_features wacom_features_0x00 =
@ -1635,6 +1813,24 @@ static const struct wacom_features wacom_features_0xBB =
static const struct wacom_features wacom_features_0xBC =
{ "Wacom Intuos4 WL", WACOM_PKGLEN_INTUOS, 40840, 25400, 2047,
63, INTUOS4, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
static const struct wacom_features wacom_features_0x26 =
{ "Wacom Intuos5 touch S", WACOM_PKGLEN_INTUOS, 31496, 19685, 2047,
63, INTUOS5S, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES,
.touch_max = 16 };
static const struct wacom_features wacom_features_0x27 =
{ "Wacom Intuos5 touch M", WACOM_PKGLEN_INTUOS, 44704, 27940, 2047,
63, INTUOS5, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES,
.touch_max = 16 };
static const struct wacom_features wacom_features_0x28 =
{ "Wacom Intuos5 touch L", WACOM_PKGLEN_INTUOS, 65024, 40640, 2047,
63, INTUOS5L, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES,
.touch_max = 16 };
static const struct wacom_features wacom_features_0x29 =
{ "Wacom Intuos5 S", WACOM_PKGLEN_INTUOS, 31496, 19685, 2047,
63, INTUOS5S, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
static const struct wacom_features wacom_features_0x2A =
{ "Wacom Intuos5 M", WACOM_PKGLEN_INTUOS, 44704, 27940, 2047,
63, INTUOS5, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
static const struct wacom_features wacom_features_0xF4 =
{ "Wacom Cintiq 24HD", WACOM_PKGLEN_INTUOS, 104480, 65600, 2047,
63, WACOM_24HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
@ -1676,13 +1872,19 @@ static const struct wacom_features wacom_features_0x9F =
0, TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
static const struct wacom_features wacom_features_0xE2 =
{ "Wacom ISDv4 E2", WACOM_PKGLEN_TPC2FG, 26202, 16325, 255,
0, TABLETPC2FG, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
0, TABLETPC2FG, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
.touch_max = 2 };
static const struct wacom_features wacom_features_0xE3 =
{ "Wacom ISDv4 E3", WACOM_PKGLEN_TPC2FG, 26202, 16325, 255,
0, TABLETPC2FG, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
0, TABLETPC2FG, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
.touch_max = 2 };
static const struct wacom_features wacom_features_0xE5 =
{ "Wacom ISDv4 E5", WACOM_PKGLEN_MTOUCH, 26202, 16325, 255,
0, MTSCREEN, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
static const struct wacom_features wacom_features_0xE6 =
{ "Wacom ISDv4 E6", WACOM_PKGLEN_TPC2FG, 27760, 15694, 255,
0, TABLETPC2FG, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
0, TABLETPC2FG, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
.touch_max = 2 };
static const struct wacom_features wacom_features_0xEC =
{ "Wacom ISDv4 EC", WACOM_PKGLEN_GRAPHIRE, 25710, 14500, 255,
0, TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
@ -1691,19 +1893,22 @@ static const struct wacom_features wacom_features_0x47 =
31, INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
static const struct wacom_features wacom_features_0x84 =
{ "Wacom Wireless Receiver", WACOM_PKGLEN_WIRELESS, 0, 0, 0,
0, WIRELESS, 0, 0 };
0, WIRELESS, 0, 0, .touch_max = 16 };
static const struct wacom_features wacom_features_0xD0 =
{ "Wacom Bamboo 2FG", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023,
31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
.touch_max = 2 };
static const struct wacom_features wacom_features_0xD1 =
{ "Wacom Bamboo 2FG 4x5", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023,
31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
.touch_max = 2 };
static const struct wacom_features wacom_features_0xD2 =
{ "Wacom Bamboo Craft", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023,
31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
static const struct wacom_features wacom_features_0xD3 =
{ "Wacom Bamboo 2FG 6x8", WACOM_PKGLEN_BBFUN, 21648, 13700, 1023,
31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
.touch_max = 2 };
static const struct wacom_features wacom_features_0xD4 =
{ "Wacom Bamboo Pen", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023,
31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
@ -1712,28 +1917,35 @@ static const struct wacom_features wacom_features_0xD5 =
31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
static const struct wacom_features wacom_features_0xD6 =
{ "Wacom BambooPT 2FG 4x5", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023,
31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
.touch_max = 2 };
static const struct wacom_features wacom_features_0xD7 =
{ "Wacom BambooPT 2FG Small", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023,
31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
.touch_max = 2 };
static const struct wacom_features wacom_features_0xD8 =
{ "Wacom Bamboo Comic 2FG", WACOM_PKGLEN_BBFUN, 21648, 13700, 1023,
31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
.touch_max = 2 };
static const struct wacom_features wacom_features_0xDA =
{ "Wacom Bamboo 2FG 4x5 SE", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023,
31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
.touch_max = 2 };
static struct wacom_features wacom_features_0xDB =
{ "Wacom Bamboo 2FG 6x8 SE", WACOM_PKGLEN_BBFUN, 21648, 13700, 1023,
31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
.touch_max = 2 };
static const struct wacom_features wacom_features_0xDD =
{ "Wacom Bamboo Connect", WACOM_PKGLEN_BBPEN, 14720, 9200, 1023,
31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
static const struct wacom_features wacom_features_0xDE =
{ "Wacom Bamboo 16FG 4x5", WACOM_PKGLEN_BBPEN, 14720, 9200, 1023,
31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
.touch_max = 16 };
static const struct wacom_features wacom_features_0xDF =
{ "Wacom Bamboo 16FG 6x8", WACOM_PKGLEN_BBPEN, 21648, 13700, 1023,
31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
.touch_max = 16 };
static const struct wacom_features wacom_features_0x6004 =
{ "ISD-V4", WACOM_PKGLEN_GRAPHIRE, 12800, 8000, 255,
0, TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
@ -1807,6 +2019,11 @@ const struct usb_device_id wacom_ids[] = {
{ USB_DEVICE_WACOM(0xBA) },
{ USB_DEVICE_WACOM(0xBB) },
{ USB_DEVICE_WACOM(0xBC) },
{ USB_DEVICE_WACOM(0x26) },
{ USB_DEVICE_WACOM(0x27) },
{ USB_DEVICE_WACOM(0x28) },
{ USB_DEVICE_WACOM(0x29) },
{ USB_DEVICE_WACOM(0x2A) },
{ USB_DEVICE_WACOM(0x3F) },
{ USB_DEVICE_WACOM(0xC5) },
{ USB_DEVICE_WACOM(0xC6) },
@ -1842,6 +2059,7 @@ const struct usb_device_id wacom_ids[] = {
{ USB_DEVICE_WACOM(0x9F) },
{ USB_DEVICE_WACOM(0xE2) },
{ USB_DEVICE_WACOM(0xE3) },
{ USB_DEVICE_WACOM(0xE5) },
{ USB_DEVICE_WACOM(0xE6) },
{ USB_DEVICE_WACOM(0xEC) },
{ USB_DEVICE_WACOM(0x47) },

View File

@ -25,6 +25,10 @@
#define WACOM_PKGLEN_BBTOUCH3 64
#define WACOM_PKGLEN_BBPEN 10
#define WACOM_PKGLEN_WIRELESS 32
#define WACOM_PKGLEN_MTOUCH 62
/* wacom data size per MT contact */
#define WACOM_BYTES_PER_MT_PACKET 11
/* device IDs */
#define STYLUS_DEVICE_ID 0x02
@ -38,8 +42,10 @@
#define WACOM_REPORT_INTUOSREAD 5
#define WACOM_REPORT_INTUOSWRITE 6
#define WACOM_REPORT_INTUOSPAD 12
#define WACOM_REPORT_INTUOS5PAD 3
#define WACOM_REPORT_TPC1FG 6
#define WACOM_REPORT_TPC2FG 13
#define WACOM_REPORT_TPCMT 13
#define WACOM_REPORT_TPCHID 15
#define WACOM_REPORT_TPCST 16
@ -65,6 +71,9 @@ enum {
INTUOS4S,
INTUOS4,
INTUOS4L,
INTUOS5S,
INTUOS5,
INTUOS5L,
WACOM_24HD,
WACOM_21UX2,
CINTIQ,
@ -72,6 +81,7 @@ enum {
WACOM_MO,
TABLETPC,
TABLETPC2FG,
MTSCREEN,
MAX_TYPE
};
@ -95,6 +105,7 @@ struct wacom_features {
int pressure_fuzz;
int distance_fuzz;
unsigned quirks;
unsigned touch_max;
};
struct wacom_shared {
@ -113,6 +124,8 @@ struct wacom_wac {
struct input_dev *input;
int pid;
int battery_capacity;
int num_contacts_left;
int *slots;
};
#endif

View File

@ -187,6 +187,23 @@ config TOUCHSCREEN_DA9034
Say Y here to enable the support for the touchscreen found
on Dialog Semiconductor DA9034 PMIC.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called da9034-ts.
config TOUCHSCREEN_DA9052
tristate "Dialog DA9052/DA9053 TSI"
depends on PMIC_DA9052
help
Say Y here to support the touchscreen found on Dialog Semiconductor
DA9052-BC and DA9053-AA/Bx PMICs.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called da9052_tsi.
config TOUCHSCREEN_DYNAPRO
tristate "Dynapro serial touchscreen"
select SERIO
@ -306,6 +323,18 @@ config TOUCHSCREEN_WACOM_W8001
To compile this driver as a module, choose M here: the
module will be called wacom_w8001.
config TOUCHSCREEN_WACOM_I2C
tristate "Wacom Tablet support (I2C)"
depends on I2C
help
Say Y here if you want to use the I2C version of the Wacom
Pen Tablet.
If unsure, say N.
To compile this driver as a module, choose M here: the module
will be called wacom_i2c.
config TOUCHSCREEN_LPC32XX
tristate "LPC32XX touchscreen controller"
depends on ARCH_LPC32XX
@ -635,6 +664,7 @@ config TOUCHSCREEN_USB_COMPOSITE
- Zytronic controllers
- Elo TouchSystems 2700 IntelliTouch
- EasyTouch USB Touch Controller from Data Modul
- e2i (Mimo monitors)
Have a look at <http://linux.chapter7.ch/touchkit/> for
a usage description and the required user-space stuff.
@ -721,7 +751,7 @@ config TOUCHSCREEN_USB_ELO
config TOUCHSCREEN_USB_E2I
default y
bool "e2i Touchscreen controller (e.g. from Mimo 740)"
bool "e2i Touchscreen controller (e.g. from Mimo 740)" if EXPERT
depends on TOUCHSCREEN_USB_COMPOSITE
config TOUCHSCREEN_USB_ZYTRONIC
@ -744,7 +774,7 @@ config TOUCHSCREEN_USB_EASYTOUCH
bool "EasyTouch USB Touch controller device support" if EMBEDDED
depends on TOUCHSCREEN_USB_COMPOSITE
help
Say Y here if you have a EasyTouch USB Touch controller device support.
Say Y here if you have an EasyTouch USB Touch controller.
If unsure, say N.
config TOUCHSCREEN_TOUCHIT213

View File

@ -22,6 +22,7 @@ obj-$(CONFIG_TOUCHSCREEN_CYTTSP_CORE) += cyttsp_core.o
obj-$(CONFIG_TOUCHSCREEN_CYTTSP_I2C) += cyttsp_i2c.o
obj-$(CONFIG_TOUCHSCREEN_CYTTSP_SPI) += cyttsp_spi.o
obj-$(CONFIG_TOUCHSCREEN_DA9034) += da9034-ts.o
obj-$(CONFIG_TOUCHSCREEN_DA9052) += da9052_tsi.o
obj-$(CONFIG_TOUCHSCREEN_DYNAPRO) += dynapro.o
obj-$(CONFIG_TOUCHSCREEN_HAMPSHIRE) += hampshire.o
obj-$(CONFIG_TOUCHSCREEN_GUNZE) += gunze.o
@ -59,6 +60,7 @@ obj-$(CONFIG_TOUCHSCREEN_TSC2005) += tsc2005.o
obj-$(CONFIG_TOUCHSCREEN_TSC2007) += tsc2007.o
obj-$(CONFIG_TOUCHSCREEN_UCB1400) += ucb1400_ts.o
obj-$(CONFIG_TOUCHSCREEN_WACOM_W8001) += wacom_w8001.o
obj-$(CONFIG_TOUCHSCREEN_WACOM_I2C) += wacom_i2c.o
obj-$(CONFIG_TOUCHSCREEN_WM831X) += wm831x-ts.o
obj-$(CONFIG_TOUCHSCREEN_WM97XX) += wm97xx-ts.o
wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9705) += wm9705.o

View File

@ -236,7 +236,6 @@ struct mxt_object {
struct mxt_message {
u8 reportid;
u8 message[7];
u8 checksum;
};
struct mxt_finger {
@ -326,17 +325,12 @@ static bool mxt_object_writable(unsigned int type)
}
static void mxt_dump_message(struct device *dev,
struct mxt_message *message)
struct mxt_message *message)
{
dev_dbg(dev, "reportid:\t0x%x\n", message->reportid);
dev_dbg(dev, "message1:\t0x%x\n", message->message[0]);
dev_dbg(dev, "message2:\t0x%x\n", message->message[1]);
dev_dbg(dev, "message3:\t0x%x\n", message->message[2]);
dev_dbg(dev, "message4:\t0x%x\n", message->message[3]);
dev_dbg(dev, "message5:\t0x%x\n", message->message[4]);
dev_dbg(dev, "message6:\t0x%x\n", message->message[5]);
dev_dbg(dev, "message7:\t0x%x\n", message->message[6]);
dev_dbg(dev, "checksum:\t0x%x\n", message->checksum);
dev_dbg(dev, "reportid: %u\tmessage: %02x %02x %02x %02x %02x %02x %02x\n",
message->reportid, message->message[0], message->message[1],
message->message[2], message->message[3], message->message[4],
message->message[5], message->message[6]);
}
static int mxt_check_bootloader(struct i2c_client *client,
@ -506,7 +500,7 @@ static int mxt_write_object(struct mxt_data *data,
u16 reg;
object = mxt_get_object(data, type);
if (!object)
if (!object || offset >= object->size + 1)
return -EINVAL;
reg = object->start_address;
@ -1049,8 +1043,8 @@ static ssize_t mxt_update_fw_store(struct device *dev,
return count;
}
static DEVICE_ATTR(object, 0444, mxt_object_show, NULL);
static DEVICE_ATTR(update_fw, 0664, NULL, mxt_update_fw_store);
static DEVICE_ATTR(object, S_IRUGO, mxt_object_show, NULL);
static DEVICE_ATTR(update_fw, S_IWUSR, NULL, mxt_update_fw_store);
static struct attribute *mxt_attrs[] = {
&dev_attr_object.attr,
@ -1201,7 +1195,7 @@ static int __devexit mxt_remove(struct i2c_client *client)
return 0;
}
#ifdef CONFIG_PM
#ifdef CONFIG_PM_SLEEP
static int mxt_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
@ -1239,13 +1233,10 @@ static int mxt_resume(struct device *dev)
return 0;
}
static const struct dev_pm_ops mxt_pm_ops = {
.suspend = mxt_suspend,
.resume = mxt_resume,
};
#endif
static SIMPLE_DEV_PM_OPS(mxt_pm_ops, mxt_suspend, mxt_resume);
static const struct i2c_device_id mxt_id[] = {
{ "qt602240_ts", 0 },
{ "atmel_mxt_ts", 0 },
@ -1258,9 +1249,7 @@ static struct i2c_driver mxt_driver = {
.driver = {
.name = "atmel_mxt_ts",
.owner = THIS_MODULE,
#ifdef CONFIG_PM
.pm = &mxt_pm_ops,
#endif
},
.probe = mxt_probe,
.remove = __devexit_p(mxt_remove),

View File

@ -0,0 +1,370 @@
/*
* TSI driver for Dialog DA9052
*
* Copyright(c) 2012 Dialog Semiconductor Ltd.
*
* Author: David Dajun Chen <dchen@diasemi.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
*/
#include <linux/module.h>
#include <linux/input.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/mfd/da9052/reg.h>
#include <linux/mfd/da9052/da9052.h>
#define TSI_PEN_DOWN_STATUS 0x40
struct da9052_tsi {
struct da9052 *da9052;
struct input_dev *dev;
struct delayed_work ts_pen_work;
struct mutex mutex;
unsigned int irq_pendwn;
unsigned int irq_datardy;
bool stopped;
bool adc_on;
};
static void da9052_ts_adc_toggle(struct da9052_tsi *tsi, bool on)
{
da9052_reg_update(tsi->da9052, DA9052_TSI_CONT_A_REG, 1 << 0, on);
tsi->adc_on = on;
}
static irqreturn_t da9052_ts_pendwn_irq(int irq, void *data)
{
struct da9052_tsi *tsi = data;
if (!tsi->stopped) {
/* Mask PEN_DOWN event and unmask TSI_READY event */
disable_irq_nosync(tsi->irq_pendwn);
enable_irq(tsi->irq_datardy);
da9052_ts_adc_toggle(tsi, true);
schedule_delayed_work(&tsi->ts_pen_work, HZ / 50);
}
return IRQ_HANDLED;
}
static void da9052_ts_read(struct da9052_tsi *tsi)
{
struct input_dev *input = tsi->dev;
int ret;
u16 x, y, z;
u8 v;
ret = da9052_reg_read(tsi->da9052, DA9052_TSI_X_MSB_REG);
if (ret < 0)
return;
x = (u16) ret;
ret = da9052_reg_read(tsi->da9052, DA9052_TSI_Y_MSB_REG);
if (ret < 0)
return;
y = (u16) ret;
ret = da9052_reg_read(tsi->da9052, DA9052_TSI_Z_MSB_REG);
if (ret < 0)
return;
z = (u16) ret;
ret = da9052_reg_read(tsi->da9052, DA9052_TSI_LSB_REG);
if (ret < 0)
return;
v = (u8) ret;
x = ((x << 2) & 0x3fc) | (v & 0x3);
y = ((y << 2) & 0x3fc) | ((v & 0xc) >> 2);
z = ((z << 2) & 0x3fc) | ((v & 0x30) >> 4);
input_report_key(input, BTN_TOUCH, 1);
input_report_abs(input, ABS_X, x);
input_report_abs(input, ABS_Y, y);
input_report_abs(input, ABS_PRESSURE, z);
input_sync(input);
}
static irqreturn_t da9052_ts_datardy_irq(int irq, void *data)
{
struct da9052_tsi *tsi = data;
da9052_ts_read(tsi);
return IRQ_HANDLED;
}
static void da9052_ts_pen_work(struct work_struct *work)
{
struct da9052_tsi *tsi = container_of(work, struct da9052_tsi,
ts_pen_work.work);
if (!tsi->stopped) {
int ret = da9052_reg_read(tsi->da9052, DA9052_TSI_LSB_REG);
if (ret < 0 || (ret & TSI_PEN_DOWN_STATUS)) {
/* Pen is still DOWN (or read error) */
schedule_delayed_work(&tsi->ts_pen_work, HZ / 50);
} else {
struct input_dev *input = tsi->dev;
/* Pen UP */
da9052_ts_adc_toggle(tsi, false);
/* Report Pen UP */
input_report_key(input, BTN_TOUCH, 0);
input_report_abs(input, ABS_PRESSURE, 0);
input_sync(input);
/*
* FIXME: Fixes the unhandled irq issue when quick
* pen down and pen up events occurs
*/
ret = da9052_reg_update(tsi->da9052,
DA9052_EVENT_B_REG, 0xC0, 0xC0);
if (ret < 0)
return;
/* Mask TSI_READY event and unmask PEN_DOWN event */
disable_irq(tsi->irq_datardy);
enable_irq(tsi->irq_pendwn);
}
}
}
static int __devinit da9052_ts_configure_gpio(struct da9052 *da9052)
{
int error;
error = da9052_reg_update(da9052, DA9052_GPIO_2_3_REG, 0x30, 0);
if (error < 0)
return error;
error = da9052_reg_update(da9052, DA9052_GPIO_4_5_REG, 0x33, 0);
if (error < 0)
return error;
error = da9052_reg_update(da9052, DA9052_GPIO_6_7_REG, 0x33, 0);
if (error < 0)
return error;
return 0;
}
static int __devinit da9052_configure_tsi(struct da9052_tsi *tsi)
{
int error;
error = da9052_ts_configure_gpio(tsi->da9052);
if (error)
return error;
/* Measure TSI sample every 1ms */
error = da9052_reg_update(tsi->da9052, DA9052_ADC_CONT_REG,
1 << 6, 1 << 6);
if (error < 0)
return error;
/* TSI_DELAY: 3 slots, TSI_SKIP: 0 slots, TSI_MODE: XYZP */
error = da9052_reg_update(tsi->da9052, DA9052_TSI_CONT_A_REG, 0xFC, 0xC0);
if (error < 0)
return error;
/* Supply TSIRef through LD09 */
error = da9052_reg_write(tsi->da9052, DA9052_LDO9_REG, 0x59);
if (error < 0)
return error;
return 0;
}
static int da9052_ts_input_open(struct input_dev *input_dev)
{
struct da9052_tsi *tsi = input_get_drvdata(input_dev);
tsi->stopped = false;
mb();
/* Unmask PEN_DOWN event */
enable_irq(tsi->irq_pendwn);
/* Enable Pen Detect Circuit */
return da9052_reg_update(tsi->da9052, DA9052_TSI_CONT_A_REG,
1 << 1, 1 << 1);
}
static void da9052_ts_input_close(struct input_dev *input_dev)
{
struct da9052_tsi *tsi = input_get_drvdata(input_dev);
tsi->stopped = true;
mb();
disable_irq(tsi->irq_pendwn);
cancel_delayed_work_sync(&tsi->ts_pen_work);
if (tsi->adc_on) {
disable_irq(tsi->irq_datardy);
da9052_ts_adc_toggle(tsi, false);
/*
* If ADC was on that means that pendwn IRQ was disabled
* twice and we need to enable it to keep enable/disable
* counter balanced. IRQ is still off though.
*/
enable_irq(tsi->irq_pendwn);
}
/* Disable Pen Detect Circuit */
da9052_reg_update(tsi->da9052, DA9052_TSI_CONT_A_REG, 1 << 1, 0);
}
static int __devinit da9052_ts_probe(struct platform_device *pdev)
{
struct da9052 *da9052;
struct da9052_tsi *tsi;
struct input_dev *input_dev;
int irq_pendwn;
int irq_datardy;
int error;
da9052 = dev_get_drvdata(pdev->dev.parent);
if (!da9052)
return -EINVAL;
irq_pendwn = platform_get_irq_byname(pdev, "PENDWN");
irq_datardy = platform_get_irq_byname(pdev, "TSIRDY");
if (irq_pendwn < 0 || irq_datardy < 0) {
dev_err(da9052->dev, "Unable to determine device interrupts\n");
return -ENXIO;
}
tsi = kzalloc(sizeof(struct da9052_tsi), GFP_KERNEL);
input_dev = input_allocate_device();
if (!tsi || !input_dev) {
error = -ENOMEM;
goto err_free_mem;
}
tsi->da9052 = da9052;
tsi->dev = input_dev;
tsi->irq_pendwn = da9052->irq_base + irq_pendwn;
tsi->irq_datardy = da9052->irq_base + irq_datardy;
tsi->stopped = true;
INIT_DELAYED_WORK(&tsi->ts_pen_work, da9052_ts_pen_work);
input_dev->id.version = 0x0101;
input_dev->id.vendor = 0x15B6;
input_dev->id.product = 0x9052;
input_dev->name = "Dialog DA9052 TouchScreen Driver";
input_dev->dev.parent = &pdev->dev;
input_dev->open = da9052_ts_input_open;
input_dev->close = da9052_ts_input_close;
__set_bit(EV_ABS, input_dev->evbit);
__set_bit(EV_KEY, input_dev->evbit);
__set_bit(BTN_TOUCH, input_dev->keybit);
input_set_abs_params(input_dev, ABS_X, 0, 1023, 0, 0);
input_set_abs_params(input_dev, ABS_Y, 0, 1023, 0, 0);
input_set_abs_params(input_dev, ABS_PRESSURE, 0, 1023, 0, 0);
input_set_drvdata(input_dev, tsi);
/* Disable Pen Detect Circuit */
da9052_reg_update(tsi->da9052, DA9052_TSI_CONT_A_REG, 1 << 1, 0);
/* Disable ADC */
da9052_ts_adc_toggle(tsi, false);
error = request_threaded_irq(tsi->irq_pendwn,
NULL, da9052_ts_pendwn_irq,
IRQF_TRIGGER_LOW | IRQF_ONESHOT,
"PENDWN", tsi);
if (error) {
dev_err(tsi->da9052->dev,
"Failed to register PENDWN IRQ %d, error = %d\n",
tsi->irq_pendwn, error);
goto err_free_mem;
}
error = request_threaded_irq(tsi->irq_datardy,
NULL, da9052_ts_datardy_irq,
IRQF_TRIGGER_LOW | IRQF_ONESHOT,
"TSIRDY", tsi);
if (error) {
dev_err(tsi->da9052->dev,
"Failed to register TSIRDY IRQ %d, error = %d\n",
tsi->irq_datardy, error);
goto err_free_pendwn_irq;
}
/* Mask PEN_DOWN and TSI_READY events */
disable_irq(tsi->irq_pendwn);
disable_irq(tsi->irq_datardy);
error = da9052_configure_tsi(tsi);
if (error)
goto err_free_datardy_irq;
error = input_register_device(tsi->dev);
if (error)
goto err_free_datardy_irq;
platform_set_drvdata(pdev, tsi);
return 0;
err_free_datardy_irq:
free_irq(tsi->irq_datardy, tsi);
err_free_pendwn_irq:
free_irq(tsi->irq_pendwn, tsi);
err_free_mem:
kfree(tsi);
input_free_device(input_dev);
return error;
}
static int __devexit da9052_ts_remove(struct platform_device *pdev)
{
struct da9052_tsi *tsi = platform_get_drvdata(pdev);
da9052_reg_write(tsi->da9052, DA9052_LDO9_REG, 0x19);
free_irq(tsi->irq_pendwn, tsi);
free_irq(tsi->irq_datardy, tsi);
input_unregister_device(tsi->dev);
kfree(tsi);
platform_set_drvdata(pdev, NULL);
return 0;
}
static struct platform_driver da9052_tsi_driver = {
.probe = da9052_ts_probe,
.remove = __devexit_p(da9052_ts_remove),
.driver = {
.name = "da9052-tsi",
.owner = THIS_MODULE,
},
};
module_platform_driver(da9052_tsi_driver);
MODULE_DESCRIPTION("Touchscreen driver for Dialog Semiconductor DA9052");
MODULE_AUTHOR("Anthony Olech <Anthony.Olech@diasemi.com>");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:da9052-tsi");

View File

@ -188,19 +188,4 @@ static struct serio_driver dynapro_drv = {
.disconnect = dynapro_disconnect,
};
/*
* The functions for inserting/removing us as a module.
*/
static int __init dynapro_init(void)
{
return serio_register_driver(&dynapro_drv);
}
static void __exit dynapro_exit(void)
{
serio_unregister_driver(&dynapro_drv);
}
module_init(dynapro_init);
module_exit(dynapro_exit);
module_serio_driver(dynapro_drv);

View File

@ -405,19 +405,4 @@ static struct serio_driver elo_drv = {
.disconnect = elo_disconnect,
};
/*
* The functions for inserting/removing us as a module.
*/
static int __init elo_init(void)
{
return serio_register_driver(&elo_drv);
}
static void __exit elo_exit(void)
{
serio_unregister_driver(&elo_drv);
}
module_init(elo_init);
module_exit(elo_exit);
module_serio_driver(elo_drv);

View File

@ -175,15 +175,4 @@ static struct serio_driver fujitsu_drv = {
.disconnect = fujitsu_disconnect,
};
static int __init fujitsu_init(void)
{
return serio_register_driver(&fujitsu_drv);
}
static void __exit fujitsu_exit(void)
{
serio_unregister_driver(&fujitsu_drv);
}
module_init(fujitsu_init);
module_exit(fujitsu_exit);
module_serio_driver(fujitsu_drv);

View File

@ -186,19 +186,4 @@ static struct serio_driver gunze_drv = {
.disconnect = gunze_disconnect,
};
/*
* The functions for inserting/removing us as a module.
*/
static int __init gunze_init(void)
{
return serio_register_driver(&gunze_drv);
}
static void __exit gunze_exit(void)
{
serio_unregister_driver(&gunze_drv);
}
module_init(gunze_init);
module_exit(gunze_exit);
module_serio_driver(gunze_drv);

View File

@ -476,19 +476,4 @@ static struct serio_driver h3600ts_drv = {
.disconnect = h3600ts_disconnect,
};
/*
* The functions for inserting/removing us as a module.
*/
static int __init h3600ts_init(void)
{
return serio_register_driver(&h3600ts_drv);
}
static void __exit h3600ts_exit(void)
{
serio_unregister_driver(&h3600ts_drv);
}
module_init(h3600ts_init);
module_exit(h3600ts_exit);
module_serio_driver(h3600ts_drv);

View File

@ -187,19 +187,4 @@ static struct serio_driver hampshire_drv = {
.disconnect = hampshire_disconnect,
};
/*
* The functions for inserting/removing us as a module.
*/
static int __init hampshire_init(void)
{
return serio_register_driver(&hampshire_drv);
}
static void __exit hampshire_exit(void)
{
serio_unregister_driver(&hampshire_drv);
}
module_init(hampshire_init);
module_exit(hampshire_exit);
module_serio_driver(hampshire_drv);

View File

@ -189,19 +189,4 @@ static struct serio_driver inexio_drv = {
.disconnect = inexio_disconnect,
};
/*
* The functions for inserting/removing us as a module.
*/
static int __init inexio_init(void)
{
return serio_register_driver(&inexio_drv);
}
static void __exit inexio_exit(void)
{
serio_unregister_driver(&inexio_drv);
}
module_init(inexio_init);
module_exit(inexio_exit);
module_serio_driver(inexio_drv);

View File

@ -22,6 +22,7 @@
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/slab.h>
#include <linux/of.h>
/*
* Touchscreen controller register offsets
@ -383,6 +384,14 @@ static const struct dev_pm_ops lpc32xx_ts_pm_ops = {
#define LPC32XX_TS_PM_OPS NULL
#endif
#ifdef CONFIG_OF
static struct of_device_id lpc32xx_tsc_of_match[] = {
{ .compatible = "nxp,lpc3220-tsc", },
{ },
};
MODULE_DEVICE_TABLE(of, lpc32xx_tsc_of_match);
#endif
static struct platform_driver lpc32xx_ts_driver = {
.probe = lpc32xx_ts_probe,
.remove = __devexit_p(lpc32xx_ts_remove),
@ -390,6 +399,7 @@ static struct platform_driver lpc32xx_ts_driver = {
.name = MOD_NAME,
.owner = THIS_MODULE,
.pm = LPC32XX_TS_PM_OPS,
.of_match_table = of_match_ptr(lpc32xx_tsc_of_match),
},
};
module_platform_driver(lpc32xx_ts_driver);

View File

@ -202,19 +202,4 @@ static struct serio_driver mtouch_drv = {
.disconnect = mtouch_disconnect,
};
/*
* The functions for inserting/removing us as a module.
*/
static int __init mtouch_init(void)
{
return serio_register_driver(&mtouch_drv);
}
static void __exit mtouch_exit(void)
{
serio_unregister_driver(&mtouch_drv);
}
module_init(mtouch_init);
module_exit(mtouch_exit);
module_serio_driver(mtouch_drv);

View File

@ -317,19 +317,4 @@ static struct serio_driver pm_drv = {
.disconnect = pm_disconnect,
};
/*
* The functions for inserting/removing us as a module.
*/
static int __init pm_init(void)
{
return serio_register_driver(&pm_drv);
}
static void __exit pm_exit(void)
{
serio_unregister_driver(&pm_drv);
}
module_init(pm_init);
module_exit(pm_exit);
module_serio_driver(pm_drv);

View File

@ -218,7 +218,7 @@ static int __devexit st1232_ts_remove(struct i2c_client *client)
return 0;
}
#ifdef CONFIG_PM
#ifdef CONFIG_PM_SLEEP
static int st1232_ts_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
@ -243,18 +243,25 @@ static int st1232_ts_resume(struct device *dev)
return 0;
}
static const struct dev_pm_ops st1232_ts_pm_ops = {
.suspend = st1232_ts_suspend,
.resume = st1232_ts_resume,
};
#endif
static SIMPLE_DEV_PM_OPS(st1232_ts_pm_ops,
st1232_ts_suspend, st1232_ts_resume);
static const struct i2c_device_id st1232_ts_id[] = {
{ ST1232_TS_NAME, 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, st1232_ts_id);
#ifdef CONFIG_OF
static const struct of_device_id st1232_ts_dt_ids[] __devinitconst = {
{ .compatible = "sitronix,st1232", },
{ }
};
MODULE_DEVICE_TABLE(of, st1232_ts_dt_ids);
#endif
static struct i2c_driver st1232_ts_driver = {
.probe = st1232_ts_probe,
.remove = __devexit_p(st1232_ts_remove),
@ -262,9 +269,8 @@ static struct i2c_driver st1232_ts_driver = {
.driver = {
.name = ST1232_TS_NAME,
.owner = THIS_MODULE,
#ifdef CONFIG_PM
.of_match_table = of_match_ptr(st1232_ts_dt_ids),
.pm = &st1232_ts_pm_ops,
#endif
},
};

View File

@ -216,19 +216,4 @@ static struct serio_driver touchit213_drv = {
.disconnect = touchit213_disconnect,
};
/*
* The functions for inserting/removing us as a module.
*/
static int __init touchit213_init(void)
{
return serio_register_driver(&touchit213_drv);
}
static void __exit touchit213_exit(void)
{
serio_unregister_driver(&touchit213_drv);
}
module_init(touchit213_init);
module_exit(touchit213_exit);
module_serio_driver(touchit213_drv);

View File

@ -176,19 +176,4 @@ static struct serio_driver tr_drv = {
.disconnect = tr_disconnect,
};
/*
* The functions for inserting/removing us as a module.
*/
static int __init tr_init(void)
{
return serio_register_driver(&tr_drv);
}
static void __exit tr_exit(void)
{
serio_unregister_driver(&tr_drv);
}
module_init(tr_init);
module_exit(tr_exit);
module_serio_driver(tr_drv);

View File

@ -183,19 +183,4 @@ static struct serio_driver tw_drv = {
.disconnect = tw_disconnect,
};
/*
* The functions for inserting/removing us as a module.
*/
static int __init tw_init(void)
{
return serio_register_driver(&tw_drv);
}
static void __exit tw_exit(void)
{
serio_unregister_driver(&tw_drv);
}
module_init(tw_init);
module_exit(tw_exit);
module_serio_driver(tw_drv);

View File

@ -167,17 +167,7 @@ static struct serio_driver tsc_drv = {
.disconnect = tsc_disconnect,
};
static int __init tsc_ser_init(void)
{
return serio_register_driver(&tsc_drv);
}
module_init(tsc_ser_init);
static void __exit tsc_exit(void)
{
serio_unregister_driver(&tsc_drv);
}
module_exit(tsc_exit);
module_serio_driver(tsc_drv);
MODULE_AUTHOR("Sebastian Andrzej Siewior <bigeasy@linutronix.de>");
MODULE_DESCRIPTION(DRIVER_DESC);

View File

@ -0,0 +1,282 @@
/*
* Wacom Penabled Driver for I2C
*
* Copyright (c) 2011 Tatsunosuke Tobita, Wacom.
* <tobita.tatsunosuke@wacom.co.jp>
*
* This program is free software; you can redistribute it
* and/or modify it under the terms of the GNU General
* Public License as published by the Free Software
* Foundation; either version of 2 of the License,
* or (at your option) any later version.
*/
#include <linux/module.h>
#include <linux/input.h>
#include <linux/i2c.h>
#include <linux/slab.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/gpio.h>
#include <asm/unaligned.h>
#define WACOM_CMD_QUERY0 0x04
#define WACOM_CMD_QUERY1 0x00
#define WACOM_CMD_QUERY2 0x33
#define WACOM_CMD_QUERY3 0x02
#define WACOM_CMD_THROW0 0x05
#define WACOM_CMD_THROW1 0x00
#define WACOM_QUERY_SIZE 19
#define WACOM_RETRY_CNT 100
struct wacom_features {
int x_max;
int y_max;
int pressure_max;
char fw_version;
};
struct wacom_i2c {
struct i2c_client *client;
struct input_dev *input;
u8 data[WACOM_QUERY_SIZE];
};
static int wacom_query_device(struct i2c_client *client,
struct wacom_features *features)
{
int ret;
u8 cmd1[] = { WACOM_CMD_QUERY0, WACOM_CMD_QUERY1,
WACOM_CMD_QUERY2, WACOM_CMD_QUERY3 };
u8 cmd2[] = { WACOM_CMD_THROW0, WACOM_CMD_THROW1 };
u8 data[WACOM_QUERY_SIZE];
struct i2c_msg msgs[] = {
{
.addr = client->addr,
.flags = 0,
.len = sizeof(cmd1),
.buf = cmd1,
},
{
.addr = client->addr,
.flags = 0,
.len = sizeof(cmd2),
.buf = cmd2,
},
{
.addr = client->addr,
.flags = I2C_M_RD,
.len = sizeof(data),
.buf = data,
},
};
ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
if (ret < 0)
return ret;
if (ret != ARRAY_SIZE(msgs))
return -EIO;
features->x_max = get_unaligned_le16(&data[3]);
features->y_max = get_unaligned_le16(&data[5]);
features->pressure_max = get_unaligned_le16(&data[11]);
features->fw_version = get_unaligned_le16(&data[13]);
dev_dbg(&client->dev,
"x_max:%d, y_max:%d, pressure:%d, fw:%d\n",
features->x_max, features->y_max,
features->pressure_max, features->fw_version);
return 0;
}
static irqreturn_t wacom_i2c_irq(int irq, void *dev_id)
{
struct wacom_i2c *wac_i2c = dev_id;
struct input_dev *input = wac_i2c->input;
u8 *data = wac_i2c->data;
unsigned int x, y, pressure;
unsigned char tsw, f1, f2, ers;
int error;
error = i2c_master_recv(wac_i2c->client,
wac_i2c->data, sizeof(wac_i2c->data));
if (error < 0)
goto out;
tsw = data[3] & 0x01;
ers = data[3] & 0x04;
f1 = data[3] & 0x02;
f2 = data[3] & 0x10;
x = le16_to_cpup((__le16 *)&data[4]);
y = le16_to_cpup((__le16 *)&data[6]);
pressure = le16_to_cpup((__le16 *)&data[8]);
input_report_key(input, BTN_TOUCH, tsw || ers);
input_report_key(input, BTN_TOOL_PEN, tsw);
input_report_key(input, BTN_TOOL_RUBBER, ers);
input_report_key(input, BTN_STYLUS, f1);
input_report_key(input, BTN_STYLUS2, f2);
input_report_abs(input, ABS_X, x);
input_report_abs(input, ABS_Y, y);
input_report_abs(input, ABS_PRESSURE, pressure);
input_sync(input);
out:
return IRQ_HANDLED;
}
static int wacom_i2c_open(struct input_dev *dev)
{
struct wacom_i2c *wac_i2c = input_get_drvdata(dev);
struct i2c_client *client = wac_i2c->client;
enable_irq(client->irq);
return 0;
}
static void wacom_i2c_close(struct input_dev *dev)
{
struct wacom_i2c *wac_i2c = input_get_drvdata(dev);
struct i2c_client *client = wac_i2c->client;
disable_irq(client->irq);
}
static int __devinit wacom_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct wacom_i2c *wac_i2c;
struct input_dev *input;
struct wacom_features features;
int error;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
dev_err(&client->dev, "i2c_check_functionality error\n");
return -EIO;
}
error = wacom_query_device(client, &features);
if (error)
return error;
wac_i2c = kzalloc(sizeof(*wac_i2c), GFP_KERNEL);
input = input_allocate_device();
if (!wac_i2c || !input) {
error = -ENOMEM;
goto err_free_mem;
}
wac_i2c->client = client;
wac_i2c->input = input;
input->name = "Wacom I2C Digitizer";
input->id.bustype = BUS_I2C;
input->id.vendor = 0x56a;
input->id.version = features.fw_version;
input->dev.parent = &client->dev;
input->open = wacom_i2c_open;
input->close = wacom_i2c_close;
input->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
__set_bit(BTN_TOOL_PEN, input->keybit);
__set_bit(BTN_TOOL_RUBBER, input->keybit);
__set_bit(BTN_STYLUS, input->keybit);
__set_bit(BTN_STYLUS2, input->keybit);
__set_bit(BTN_TOUCH, input->keybit);
input_set_abs_params(input, ABS_X, 0, features.x_max, 0, 0);
input_set_abs_params(input, ABS_Y, 0, features.y_max, 0, 0);
input_set_abs_params(input, ABS_PRESSURE,
0, features.pressure_max, 0, 0);
input_set_drvdata(input, wac_i2c);
error = request_threaded_irq(client->irq, NULL, wacom_i2c_irq,
IRQF_TRIGGER_LOW | IRQF_ONESHOT,
"wacom_i2c", wac_i2c);
if (error) {
dev_err(&client->dev,
"Failed to enable IRQ, error: %d\n", error);
goto err_free_mem;
}
/* Disable the IRQ, we'll enable it in wac_i2c_open() */
disable_irq(client->irq);
error = input_register_device(wac_i2c->input);
if (error) {
dev_err(&client->dev,
"Failed to register input device, error: %d\n", error);
goto err_free_irq;
}
i2c_set_clientdata(client, wac_i2c);
return 0;
err_free_irq:
free_irq(client->irq, wac_i2c);
err_free_mem:
input_free_device(input);
kfree(wac_i2c);
return error;
}
static int __devexit wacom_i2c_remove(struct i2c_client *client)
{
struct wacom_i2c *wac_i2c = i2c_get_clientdata(client);
free_irq(client->irq, wac_i2c);
input_unregister_device(wac_i2c->input);
kfree(wac_i2c);
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int wacom_i2c_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
disable_irq(client->irq);
return 0;
}
static int wacom_i2c_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
enable_irq(client->irq);
return 0;
}
#endif
static SIMPLE_DEV_PM_OPS(wacom_i2c_pm, wacom_i2c_suspend, wacom_i2c_resume);
static const struct i2c_device_id wacom_i2c_id[] = {
{ "WAC_I2C_EMR", 0 },
{ },
};
MODULE_DEVICE_TABLE(i2c, wacom_i2c_id);
static struct i2c_driver wacom_i2c_driver = {
.driver = {
.name = "wacom_i2c",
.owner = THIS_MODULE,
.pm = &wacom_i2c_pm,
},
.probe = wacom_i2c_probe,
.remove = __devexit_p(wacom_i2c_remove),
.id_table = wacom_i2c_id,
};
module_i2c_driver(wacom_i2c_driver);
MODULE_AUTHOR("Tatsunosuke Tobita <tobita.tatsunosuke@wacom.co.jp>");
MODULE_DESCRIPTION("WACOM EMR I2C Driver");
MODULE_LICENSE("GPL");

View File

@ -594,15 +594,4 @@ static struct serio_driver w8001_drv = {
.disconnect = w8001_disconnect,
};
static int __init w8001_init(void)
{
return serio_register_driver(&w8001_drv);
}
static void __exit w8001_exit(void)
{
serio_unregister_driver(&w8001_drv);
}
module_init(w8001_init);
module_exit(w8001_exit);
module_serio_driver(w8001_drv);

Some files were not shown because too many files have changed in this diff Show More