diff options
32 files changed, 1438 insertions, 498 deletions
diff --git a/Documentation/input/walkera0701.txt b/Documentation/input/walkera0701.txt new file mode 100644 index 00000000000..8f4289efc5c --- /dev/null +++ b/Documentation/input/walkera0701.txt @@ -0,0 +1,109 @@ + +Walkera WK-0701 transmitter is supplied with a ready to fly Walkera +helicopters such as HM36, HM37, HM60. The walkera0701 module enables to use +this transmitter as joystick + +Devel homepage and download: +http://zub.fei.tuke.sk/walkera-wk0701/ + +or use cogito: +cg-clone http://zub.fei.tuke.sk/GIT/walkera0701-joystick + + +Connecting to PC: + +At back side of transmitter S-video connector can be found. Modulation +pulses from processor to HF part can be found at pin 2 of this connector, +pin 3 is GND. Between pin 3 and CPU 5k6 resistor can be found. To get +modulation pulses to PC, signal pulses must be amplified. + +Cable: (walkera TX to parport) + +Walkera WK-0701 TX S-VIDEO connector: + (back side of TX) +     __   __              S-video:                                  canon25 +    /  |_|  \             pin 2 (signal)              NPN           parport +   / O 4 3 O \            pin 3 (GND)        LED        ________________  10 ACK +  ( O 2   1 O )                                         | C +   \   ___   /      2 ________________________|\|_____|/ +    | [___] |                                 |/|   B |\ +     -------        3 __________________________________|________________ 25 GND +                                                          E + + +I use green LED and BC109 NPN transistor. + +Software: + +Build kernel with walkera0701 module. Module walkera0701 need exclusive +access to parport, modules like lp must be unloaded before loading +walkera0701 module, check dmesg for error messages. Connect TX to PC by +cable and run jstest /dev/input/js0 to see values from TX. If no value can +be changed by TX "joystick", check output from /proc/interrupts. Value for +(usually irq7) parport must increase if TX is on. + + + +Technical details: + +Driver use interrupt from parport ACK input bit to measure pulse length +using hrtimers. + +Frame format: +Based on walkera WK-0701 PCM Format description by Shaul Eizikovich. +(downloaded from http://www.smartpropoplus.com/Docs/Walkera_Wk-0701_PCM.pdf) + +Signal pulses: +                   (ANALOG) +    SYNC      BIN   OCT +  +---------+      +------+ +  |         |      |      | +--+         +------+      +--- + +Frame: + SYNC , BIN1, OCT1, BIN2, OCT2 ... BIN24, OCT24, BIN25, next frame SYNC .. + +pulse length: +   Binary values:		Analog octal values: + +   288 uS Binary 0		318 uS       000 +   438 uS Binary 1		398 uS       001 +				478 uS       010 +				558 uS       011 +				638 uS       100 +  1306 uS SYNC			718 uS       101 +				798 uS       110 +				878 uS       111 + +24 bin+oct values + 1 bin value = 24*4+1 bits  = 97 bits + +(Warning, pulses on ACK ar inverted by transistor, irq is rised up on sync +to bin change or octal value to bin change). + +Binary data representations: + +One binary and octal value can be grouped to nibble. 24 nibbles + one binary +values can be sampled between sync pulses. + +Values for first four channels (analog joystick values) can be found in +first 10 nibbles. Analog value is represented by one sign bit and 9 bit +absolute binary value. (10 bits per channel). Next nibble is checksum for +first ten nibbles. + +Next nibbles 12 .. 21 represents four channels (not all channels can be +directly controlled from TX). Binary representations ar the same as in first +four channels. In nibbles 22 and 23 is a special magic number. Nibble 24 is +checksum for nibbles 12..23. + +After last octal value for nibble 24 and next sync pulse one additional +binary value can be sampled. This bit and magic number is not used in +software driver. Some details about this magic numbers can be found in +Walkera_Wk-0701_PCM.pdf. + +Checksum calculation: + +Summary of octal values in nibbles must be same as octal value in checksum +nibble (only first 3 bits are used). Binary value for checksum nibble is +calculated by sum of binary values in checked nibbles + sum of octal values +in checked nibbles divided by 8. Only bit 0 of this sum is used. + diff --git a/drivers/input/Makefile b/drivers/input/Makefile index 98c4f9a7787..4c9c745a702 100644 --- a/drivers/input/Makefile +++ b/drivers/input/Makefile @@ -5,7 +5,7 @@  # Each configuration option enables a list of files.  obj-$(CONFIG_INPUT)		+= input-core.o -input-core-objs := input.o ff-core.o +input-core-objs := input.o input-compat.o ff-core.o  obj-$(CONFIG_INPUT_FF_MEMLESS)	+= ff-memless.o  obj-$(CONFIG_INPUT_POLLDEV)	+= input-polldev.o diff --git a/drivers/input/evbug.c b/drivers/input/evbug.c index 0353601ac3b..f7c5c14ec12 100644 --- a/drivers/input/evbug.c +++ b/drivers/input/evbug.c @@ -39,7 +39,7 @@ MODULE_LICENSE("GPL");  static void evbug_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)  {  	printk(KERN_DEBUG "evbug.c: Event. Dev: %s, Type: %d, Code: %d, Value: %d\n", -		handle->dev->dev.bus_id, type, code, value); +		dev_name(&handle->dev->dev), type, code, value);  }  static int evbug_connect(struct input_handler *handler, struct input_dev *dev, @@ -65,7 +65,7 @@ static int evbug_connect(struct input_handler *handler, struct input_dev *dev,  		goto err_unregister_handle;  	printk(KERN_DEBUG "evbug.c: Connected device: %s (%s at %s)\n", -		dev->dev.bus_id, +		dev_name(&dev->dev),  		dev->name ?: "unknown",  		dev->phys ?: "unknown"); @@ -81,7 +81,7 @@ static int evbug_connect(struct input_handler *handler, struct input_dev *dev,  static void evbug_disconnect(struct input_handle *handle)  {  	printk(KERN_DEBUG "evbug.c: Disconnected device: %s\n", -		handle->dev->dev.bus_id); +		dev_name(&handle->dev->dev));  	input_close_device(handle);  	input_unregister_handle(handle); diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index 1070db330d3..ed8baa0aec3 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c @@ -19,7 +19,7 @@  #include <linux/input.h>  #include <linux/major.h>  #include <linux/device.h> -#include <linux/compat.h> +#include "input-compat.h"  struct evdev {  	int exist; @@ -290,187 +290,6 @@ static int evdev_open(struct inode *inode, struct file *file)  	return error;  } -#ifdef CONFIG_COMPAT - -struct input_event_compat { -	struct compat_timeval time; -	__u16 type; -	__u16 code; -	__s32 value; -}; - -struct ff_periodic_effect_compat { -	__u16 waveform; -	__u16 period; -	__s16 magnitude; -	__s16 offset; -	__u16 phase; - -	struct ff_envelope envelope; - -	__u32 custom_len; -	compat_uptr_t custom_data; -}; - -struct ff_effect_compat { -	__u16 type; -	__s16 id; -	__u16 direction; -	struct ff_trigger trigger; -	struct ff_replay replay; - -	union { -		struct ff_constant_effect constant; -		struct ff_ramp_effect ramp; -		struct ff_periodic_effect_compat periodic; -		struct ff_condition_effect condition[2]; /* One for each axis */ -		struct ff_rumble_effect rumble; -	} u; -}; - -/* Note to the author of this code: did it ever occur to -   you why the ifdefs are needed? Think about it again. -AK */ -#ifdef CONFIG_X86_64 -#  define COMPAT_TEST is_compat_task() -#elif defined(CONFIG_IA64) -#  define COMPAT_TEST IS_IA32_PROCESS(task_pt_regs(current)) -#elif defined(CONFIG_S390) -#  define COMPAT_TEST test_thread_flag(TIF_31BIT) -#elif defined(CONFIG_MIPS) -#  define COMPAT_TEST test_thread_flag(TIF_32BIT_ADDR) -#else -#  define COMPAT_TEST test_thread_flag(TIF_32BIT) -#endif - -static inline size_t evdev_event_size(void) -{ -	return COMPAT_TEST ? -		sizeof(struct input_event_compat) : sizeof(struct input_event); -} - -static int evdev_event_from_user(const char __user *buffer, -				 struct input_event *event) -{ -	if (COMPAT_TEST) { -		struct input_event_compat compat_event; - -		if (copy_from_user(&compat_event, buffer, -				   sizeof(struct input_event_compat))) -			return -EFAULT; - -		event->time.tv_sec = compat_event.time.tv_sec; -		event->time.tv_usec = compat_event.time.tv_usec; -		event->type = compat_event.type; -		event->code = compat_event.code; -		event->value = compat_event.value; - -	} else { -		if (copy_from_user(event, buffer, sizeof(struct input_event))) -			return -EFAULT; -	} - -	return 0; -} - -static int evdev_event_to_user(char __user *buffer, -				const struct input_event *event) -{ -	if (COMPAT_TEST) { -		struct input_event_compat compat_event; - -		compat_event.time.tv_sec = event->time.tv_sec; -		compat_event.time.tv_usec = event->time.tv_usec; -		compat_event.type = event->type; -		compat_event.code = event->code; -		compat_event.value = event->value; - -		if (copy_to_user(buffer, &compat_event, -				 sizeof(struct input_event_compat))) -			return -EFAULT; - -	} else { -		if (copy_to_user(buffer, event, sizeof(struct input_event))) -			return -EFAULT; -	} - -	return 0; -} - -static int evdev_ff_effect_from_user(const char __user *buffer, size_t size, -				     struct ff_effect *effect) -{ -	if (COMPAT_TEST) { -		struct ff_effect_compat *compat_effect; - -		if (size != sizeof(struct ff_effect_compat)) -			return -EINVAL; - -		/* -		 * It so happens that the pointer which needs to be changed -		 * is the last field in the structure, so we can copy the -		 * whole thing and replace just the pointer. -		 */ - -		compat_effect = (struct ff_effect_compat *)effect; - -		if (copy_from_user(compat_effect, buffer, -				   sizeof(struct ff_effect_compat))) -			return -EFAULT; - -		if (compat_effect->type == FF_PERIODIC && -		    compat_effect->u.periodic.waveform == FF_CUSTOM) -			effect->u.periodic.custom_data = -				compat_ptr(compat_effect->u.periodic.custom_data); -	} else { -		if (size != sizeof(struct ff_effect)) -			return -EINVAL; - -		if (copy_from_user(effect, buffer, sizeof(struct ff_effect))) -			return -EFAULT; -	} - -	return 0; -} - -#else - -static inline size_t evdev_event_size(void) -{ -	return sizeof(struct input_event); -} - -static int evdev_event_from_user(const char __user *buffer, -				 struct input_event *event) -{ -	if (copy_from_user(event, buffer, sizeof(struct input_event))) -		return -EFAULT; - -	return 0; -} - -static int evdev_event_to_user(char __user *buffer, -				const struct input_event *event) -{ -	if (copy_to_user(buffer, event, sizeof(struct input_event))) -		return -EFAULT; - -	return 0; -} - -static int evdev_ff_effect_from_user(const char __user *buffer, size_t size, -				     struct ff_effect *effect) -{ -	if (size != sizeof(struct ff_effect)) -		return -EINVAL; - -	if (copy_from_user(effect, buffer, sizeof(struct ff_effect))) -		return -EFAULT; - -	return 0; -} - -#endif /* CONFIG_COMPAT */ -  static ssize_t evdev_write(struct file *file, const char __user *buffer,  			   size_t count, loff_t *ppos)  { @@ -490,14 +309,14 @@ static ssize_t evdev_write(struct file *file, const char __user *buffer,  	while (retval < count) { -		if (evdev_event_from_user(buffer + retval, &event)) { +		if (input_event_from_user(buffer + retval, &event)) {  			retval = -EFAULT;  			goto out;  		}  		input_inject_event(&evdev->handle,  				   event.type, event.code, event.value); -		retval += evdev_event_size(); +		retval += input_event_size();  	}   out: @@ -531,7 +350,7 @@ static ssize_t evdev_read(struct file *file, char __user *buffer,  	struct input_event event;  	int retval; -	if (count < evdev_event_size()) +	if (count < input_event_size())  		return -EINVAL;  	if (client->head == client->tail && evdev->exist && @@ -546,13 +365,13 @@ static ssize_t evdev_read(struct file *file, char __user *buffer,  	if (!evdev->exist)  		return -ENODEV; -	while (retval + evdev_event_size() <= count && +	while (retval + input_event_size() <= count &&  	       evdev_fetch_next_event(client, &event)) { -		if (evdev_event_to_user(buffer + retval, &event)) +		if (input_event_to_user(buffer + retval, &event))  			return -EFAULT; -		retval += evdev_event_size(); +		retval += input_event_size();  	}  	return retval; @@ -823,7 +642,7 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd,  			if (_IOC_NR(cmd) == _IOC_NR(EVIOCSFF)) { -				if (evdev_ff_effect_from_user(p, _IOC_SIZE(cmd), &effect)) +				if (input_ff_effect_from_user(p, _IOC_SIZE(cmd), &effect))  					return -EFAULT;  				error = input_ff_upload(dev, &effect, file); @@ -1000,7 +819,7 @@ static int evdev_connect(struct input_handler *handler, struct input_dev *dev,  	evdev->handle.handler = handler;  	evdev->handle.private = evdev; -	strlcpy(evdev->dev.bus_id, evdev->name, sizeof(evdev->dev.bus_id)); +	dev_set_name(&evdev->dev, evdev->name);  	evdev->dev.devt = MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor);  	evdev->dev.class = &input_class;  	evdev->dev.parent = &dev->dev; diff --git a/drivers/input/gameport/gameport.c b/drivers/input/gameport/gameport.c index 2880eaae157..ebf4be5b7c4 100644 --- a/drivers/input/gameport/gameport.c +++ b/drivers/input/gameport/gameport.c @@ -530,8 +530,7 @@ static void gameport_init_port(struct gameport *gameport)  	mutex_init(&gameport->drv_mutex);  	device_initialize(&gameport->dev); -	snprintf(gameport->dev.bus_id, sizeof(gameport->dev.bus_id), -		 "gameport%lu", (unsigned long)atomic_inc_return(&gameport_no) - 1); +	dev_set_name(&gameport->dev, "gameport%lu", (unsigned long)atomic_inc_return(&gameport_no) - 1);  	gameport->dev.bus = &gameport_bus;  	gameport->dev.release = gameport_release_port;  	if (gameport->parent) diff --git a/drivers/input/gameport/ns558.c b/drivers/input/gameport/ns558.c index 2b282cde4b8..db556b71ddd 100644 --- a/drivers/input/gameport/ns558.c +++ b/drivers/input/gameport/ns558.c @@ -226,7 +226,7 @@ static int ns558_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *did)  	ns558->gameport = port;  	gameport_set_name(port, "NS558 PnP Gameport"); -	gameport_set_phys(port, "pnp%s/gameport0", dev->dev.bus_id); +	gameport_set_phys(port, "pnp%s/gameport0", dev_name(&dev->dev));  	port->dev.parent = &dev->dev;  	port->io = ioport; diff --git a/drivers/input/input-compat.c b/drivers/input/input-compat.c new file mode 100644 index 00000000000..1accb89ae66 --- /dev/null +++ b/drivers/input/input-compat.c @@ -0,0 +1,135 @@ +/* + * 32bit compatibility wrappers for the input subsystem. + * + * Very heavily based on evdev.c - Copyright (c) 1999-2002 Vojtech Pavlik + * + * 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 <asm/uaccess.h> +#include "input-compat.h" + +#ifdef CONFIG_COMPAT + +int input_event_from_user(const char __user *buffer, +			  struct input_event *event) +{ +	if (INPUT_COMPAT_TEST) { +		struct input_event_compat compat_event; + +		if (copy_from_user(&compat_event, buffer, +				   sizeof(struct input_event_compat))) +			return -EFAULT; + +		event->time.tv_sec = compat_event.time.tv_sec; +		event->time.tv_usec = compat_event.time.tv_usec; +		event->type = compat_event.type; +		event->code = compat_event.code; +		event->value = compat_event.value; + +	} else { +		if (copy_from_user(event, buffer, sizeof(struct input_event))) +			return -EFAULT; +	} + +	return 0; +} + +int input_event_to_user(char __user *buffer, +			const struct input_event *event) +{ +	if (INPUT_COMPAT_TEST) { +		struct input_event_compat compat_event; + +		compat_event.time.tv_sec = event->time.tv_sec; +		compat_event.time.tv_usec = event->time.tv_usec; +		compat_event.type = event->type; +		compat_event.code = event->code; +		compat_event.value = event->value; + +		if (copy_to_user(buffer, &compat_event, +				 sizeof(struct input_event_compat))) +			return -EFAULT; + +	} else { +		if (copy_to_user(buffer, event, sizeof(struct input_event))) +			return -EFAULT; +	} + +	return 0; +} + +int input_ff_effect_from_user(const char __user *buffer, size_t size, +			      struct ff_effect *effect) +{ +	if (INPUT_COMPAT_TEST) { +		struct ff_effect_compat *compat_effect; + +		if (size != sizeof(struct ff_effect_compat)) +			return -EINVAL; + +		/* +		 * It so happens that the pointer which needs to be changed +		 * is the last field in the structure, so we can retrieve the +		 * whole thing and replace just the pointer. +		 */ +		compat_effect = (struct ff_effect_compat *)effect; + +		if (copy_from_user(compat_effect, buffer, +				   sizeof(struct ff_effect_compat))) +			return -EFAULT; + +		if (compat_effect->type == FF_PERIODIC && +		    compat_effect->u.periodic.waveform == FF_CUSTOM) +			effect->u.periodic.custom_data = +				compat_ptr(compat_effect->u.periodic.custom_data); +	} else { +		if (size != sizeof(struct ff_effect)) +			return -EINVAL; + +		if (copy_from_user(effect, buffer, sizeof(struct ff_effect))) +			return -EFAULT; +	} + +	return 0; +} + +#else + +int input_event_from_user(const char __user *buffer, +			 struct input_event *event) +{ +	if (copy_from_user(event, buffer, sizeof(struct input_event))) +		return -EFAULT; + +	return 0; +} + +int input_event_to_user(char __user *buffer, +			const struct input_event *event) +{ +	if (copy_to_user(buffer, event, sizeof(struct input_event))) +		return -EFAULT; + +	return 0; +} + +int input_ff_effect_from_user(const char __user *buffer, size_t size, +			      struct ff_effect *effect) +{ +	if (size != sizeof(struct ff_effect)) +		return -EINVAL; + +	if (copy_from_user(effect, buffer, sizeof(struct ff_effect))) +		return -EFAULT; + +	return 0; +} + +#endif /* CONFIG_COMPAT */ + +EXPORT_SYMBOL_GPL(input_event_from_user); +EXPORT_SYMBOL_GPL(input_event_to_user); +EXPORT_SYMBOL_GPL(input_ff_effect_from_user); diff --git a/drivers/input/input-compat.h b/drivers/input/input-compat.h new file mode 100644 index 00000000000..47cd9eaee66 --- /dev/null +++ b/drivers/input/input-compat.h @@ -0,0 +1,94 @@ +#ifndef _INPUT_COMPAT_H +#define _INPUT_COMPAT_H + +/* + * 32bit compatibility wrappers for the input subsystem. + * + * Very heavily based on evdev.c - Copyright (c) 1999-2002 Vojtech Pavlik + * + * 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/compiler.h> +#include <linux/compat.h> +#include <linux/input.h> + +#ifdef CONFIG_COMPAT + +/* Note to the author of this code: did it ever occur to +   you why the ifdefs are needed? Think about it again. -AK */ +#ifdef CONFIG_X86_64 +#  define INPUT_COMPAT_TEST is_compat_task() +#elif defined(CONFIG_IA64) +#  define INPUT_COMPAT_TEST IS_IA32_PROCESS(task_pt_regs(current)) +#elif defined(CONFIG_S390) +#  define INPUT_COMPAT_TEST test_thread_flag(TIF_31BIT) +#elif defined(CONFIG_MIPS) +#  define INPUT_COMPAT_TEST test_thread_flag(TIF_32BIT_ADDR) +#else +#  define INPUT_COMPAT_TEST test_thread_flag(TIF_32BIT) +#endif + +struct input_event_compat { +	struct compat_timeval time; +	__u16 type; +	__u16 code; +	__s32 value; +}; + +struct ff_periodic_effect_compat { +	__u16 waveform; +	__u16 period; +	__s16 magnitude; +	__s16 offset; +	__u16 phase; + +	struct ff_envelope envelope; + +	__u32 custom_len; +	compat_uptr_t custom_data; +}; + +struct ff_effect_compat { +	__u16 type; +	__s16 id; +	__u16 direction; +	struct ff_trigger trigger; +	struct ff_replay replay; + +	union { +		struct ff_constant_effect constant; +		struct ff_ramp_effect ramp; +		struct ff_periodic_effect_compat periodic; +		struct ff_condition_effect condition[2]; /* One for each axis */ +		struct ff_rumble_effect rumble; +	} u; +}; + +static inline size_t input_event_size(void) +{ +	return INPUT_COMPAT_TEST ? +		sizeof(struct input_event_compat) : sizeof(struct input_event); +} + +#else + +static inline size_t input_event_size(void) +{ +	return sizeof(struct input_event); +} + +#endif /* CONFIG_COMPAT */ + +int input_event_from_user(const char __user *buffer, +			 struct input_event *event); + +int input_event_to_user(char __user *buffer, +			const struct input_event *event); + +int input_ff_effect_from_user(const char __user *buffer, size_t size, +			      struct ff_effect *effect); + +#endif /* _INPUT_COMPAT_H */ diff --git a/drivers/input/input.c b/drivers/input/input.c index c13ced3e0d3..1730d7331a5 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -1389,8 +1389,8 @@ int input_register_device(struct input_dev *dev)  	if (!dev->setkeycode)  		dev->setkeycode = input_default_setkeycode; -	snprintf(dev->dev.bus_id, sizeof(dev->dev.bus_id), -		 "input%ld", (unsigned long) atomic_inc_return(&input_no) - 1); +	dev_set_name(&dev->dev, "input%ld", +		     (unsigned long) atomic_inc_return(&input_no) - 1);  	error = device_add(&dev->dev);  	if (error) diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c index a85b1485e77..6f2366220a5 100644 --- a/drivers/input/joydev.c +++ b/drivers/input/joydev.c @@ -800,7 +800,7 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev,  		}  	} -	strlcpy(joydev->dev.bus_id, joydev->name, sizeof(joydev->dev.bus_id)); +	dev_set_name(&joydev->dev, joydev->name);  	joydev->dev.devt = MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + minor);  	joydev->dev.class = &input_class;  	joydev->dev.parent = &dev->dev; diff --git a/drivers/input/joystick/Kconfig b/drivers/input/joystick/Kconfig index be5c14a5a0a..268dd3fef0a 100644 --- a/drivers/input/joystick/Kconfig +++ b/drivers/input/joystick/Kconfig @@ -294,4 +294,16 @@ config JOYSTICK_XPAD_LEDS  	  This option enables support for the LED which surrounds the Big X on  	  XBox 360 controller. +config JOYSTICK_WALKERA0701 +	tristate "Walkera WK-0701 RC transmitter" +	depends on HIGH_RES_TIMERS && PARPORT +	help +	  Say Y or M here if you have a Walkera WK-0701 transmitter which is +	  supplied with a ready to fly Walkera helicopters such as HM36, +	  HM37, HM60 and want to use it via parport as a joystick. More +	  information is available: <file:Documentation/input/walkera0701.txt> + +	  To compile this driver as a module, choose M here: the +	  module will be called walkera0701. +  endif diff --git a/drivers/input/joystick/Makefile b/drivers/input/joystick/Makefile index fdbf8c4c287..72303629568 100644 --- a/drivers/input/joystick/Makefile +++ b/drivers/input/joystick/Makefile @@ -29,4 +29,5 @@ obj-$(CONFIG_JOYSTICK_TWIDJOY)		+= twidjoy.o  obj-$(CONFIG_JOYSTICK_WARRIOR)		+= warrior.o  obj-$(CONFIG_JOYSTICK_XPAD)		+= xpad.o  obj-$(CONFIG_JOYSTICK_ZHENHUA)		+= zhenhua.o +obj-$(CONFIG_JOYSTICK_WALKERA0701)	+= walkera0701.o diff --git a/drivers/input/joystick/walkera0701.c b/drivers/input/joystick/walkera0701.c new file mode 100644 index 00000000000..4dfa1eed4b7 --- /dev/null +++ b/drivers/input/joystick/walkera0701.c @@ -0,0 +1,292 @@ +/* + *  Parallel port to Walkera WK-0701 TX joystick + * + *  Copyright (c) 2008 Peter Popovec + * + *  More about driver:  <file:Documentation/input/walkera0701.txt> + */ + +/* + * 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. +*/ + +/* #define WK0701_DEBUG */ + +#define RESERVE 20000 +#define SYNC_PULSE 1306000 +#define BIN0_PULSE 288000 +#define BIN1_PULSE 438000 + +#define ANALOG_MIN_PULSE 318000 +#define ANALOG_MAX_PULSE 878000 +#define ANALOG_DELTA 80000 + +#define BIN_SAMPLE ((BIN0_PULSE + BIN1_PULSE) / 2) + +#define NO_SYNC 25 + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/parport.h> +#include <linux/input.h> +#include <linux/hrtimer.h> + +MODULE_AUTHOR("Peter Popovec <popovec@fei.tuke.sk>"); +MODULE_DESCRIPTION("Walkera WK-0701 TX as joystick"); +MODULE_LICENSE("GPL"); + +static unsigned int walkera0701_pp_no; +module_param_named(port, walkera0701_pp_no, int, 0); +MODULE_PARM_DESC(port, +		 "Parallel port adapter for Walkera WK-0701 TX (default is 0)"); + +/* + * For now, only one device is supported, if somebody need more devices, code + * can be expanded, one struct walkera_dev per device must be allocated and + * set up by walkera0701_connect (release of device by walkera0701_disconnect) + */ + +struct walkera_dev { +	unsigned char buf[25]; +	u64 irq_time, irq_lasttime; +	int counter; +	int ack; + +	struct input_dev *input_dev; +	struct hrtimer timer; + +	struct parport *parport; +	struct pardevice *pardevice; +}; + +static struct walkera_dev w_dev; + +static inline void walkera0701_parse_frame(struct walkera_dev *w) +{ +	int i; +	int val1, val2, val3, val4, val5, val6, val7, val8; +	int crc1, crc2; + +	for (crc1 = crc2 = i = 0; i < 10; i++) { +		crc1 += w->buf[i] & 7; +		crc2 += (w->buf[i] & 8) >> 3; +	} +	if ((w->buf[10] & 7) != (crc1 & 7)) +		return; +	if (((w->buf[10] & 8) >> 3) != (((crc1 >> 3) + crc2) & 1)) +		return; +	for (crc1 = crc2 = 0, i = 11; i < 23; i++) { +		crc1 += w->buf[i] & 7; +		crc2 += (w->buf[i] & 8) >> 3; +	} +	if ((w->buf[23] & 7) != (crc1 & 7)) +		return; +	if (((w->buf[23] & 8) >> 3) != (((crc1 >> 3) + crc2) & 1)) +		return; +	val1 = ((w->buf[0] & 7) * 256 + w->buf[1] * 16 + w->buf[2]) >> 2; +	val1 *= ((w->buf[0] >> 2) & 2) - 1;	/* sign */ +	val2 = (w->buf[2] & 1) << 8 | (w->buf[3] << 4) | w->buf[4]; +	val2 *= (w->buf[2] & 2) - 1;	/* sign */ +	val3 = ((w->buf[5] & 7) * 256 + w->buf[6] * 16 + w->buf[7]) >> 2; +	val3 *= ((w->buf[5] >> 2) & 2) - 1;	/* sign */ +	val4 = (w->buf[7] & 1) << 8 | (w->buf[8] << 4) | w->buf[9]; +	val4 *= (w->buf[7] & 2) - 1;	/* sign */ +	val5 = ((w->buf[11] & 7) * 256 + w->buf[12] * 16 + w->buf[13]) >> 2; +	val5 *= ((w->buf[11] >> 2) & 2) - 1;	/* sign */ +	val6 = (w->buf[13] & 1) << 8 | (w->buf[14] << 4) | w->buf[15]; +	val6 *= (w->buf[13] & 2) - 1;	/* sign */ +	val7 = ((w->buf[16] & 7) * 256 + w->buf[17] * 16 + w->buf[18]) >> 2; +	val7 *= ((w->buf[16] >> 2) & 2) - 1;	/*sign */ +	val8 = (w->buf[18] & 1) << 8 | (w->buf[19] << 4) | w->buf[20]; +	val8 *= (w->buf[18] & 2) - 1;	/*sign */ + +#ifdef WK0701_DEBUG +	{ +		int magic, magic_bit; +		magic = (w->buf[21] << 4) | w->buf[22]; +		magic_bit = (w->buf[24] & 8) >> 3; +		printk(KERN_DEBUG +		       "walkera0701: %4d %4d %4d %4d  %4d %4d %4d %4d (magic %2x %d)\n", +		       val1, val2, val3, val4, val5, val6, val7, val8, magic, +		       magic_bit); +	} +#endif +	input_report_abs(w->input_dev, ABS_X, val2); +	input_report_abs(w->input_dev, ABS_Y, val1); +	input_report_abs(w->input_dev, ABS_Z, val6); +	input_report_abs(w->input_dev, ABS_THROTTLE, val3); +	input_report_abs(w->input_dev, ABS_RUDDER, val4); +	input_report_abs(w->input_dev, ABS_MISC, val7); +	input_report_key(w->input_dev, BTN_GEAR_DOWN, val5 > 0); +} + +static inline int read_ack(struct pardevice *p) +{ +	return parport_read_status(p->port) & 0x40; +} + +/* falling edge, prepare to BIN value calculation */ +static void walkera0701_irq_handler(void *handler_data) +{ +	u64 pulse_time; +	struct walkera_dev *w = handler_data; + +	w->irq_time = ktime_to_ns(ktime_get()); +	pulse_time = w->irq_time - w->irq_lasttime; +	w->irq_lasttime = w->irq_time; + +	/* cancel timer, if in handler or active do resync */ +	if (unlikely(0 != hrtimer_try_to_cancel(&w->timer))) { +		w->counter = NO_SYNC; +		return; +	} + +	if (w->counter < NO_SYNC) { +		if (w->ack) { +			pulse_time -= BIN1_PULSE; +			w->buf[w->counter] = 8; +		} else { +			pulse_time -= BIN0_PULSE; +			w->buf[w->counter] = 0; +		} +		if (w->counter == 24) {	/* full frame */ +			walkera0701_parse_frame(w); +			w->counter = NO_SYNC; +			if (abs(pulse_time - SYNC_PULSE) < RESERVE)	/* new frame sync */ +				w->counter = 0; +		} else { +			if ((pulse_time > (ANALOG_MIN_PULSE - RESERVE) +			     && (pulse_time < (ANALOG_MAX_PULSE + RESERVE)))) { +				pulse_time -= (ANALOG_MIN_PULSE - RESERVE); +				pulse_time = (u32) pulse_time / ANALOG_DELTA;	/* overtiping is safe, pulsetime < s32.. */ +				w->buf[w->counter++] |= (pulse_time & 7); +			} else +				w->counter = NO_SYNC; +		} +	} else if (abs(pulse_time - SYNC_PULSE - BIN0_PULSE) < +				RESERVE + BIN1_PULSE - BIN0_PULSE)	/* frame sync .. */ +		w->counter = 0; + +	hrtimer_start(&w->timer, ktime_set(0, BIN_SAMPLE), HRTIMER_MODE_REL); +} + +static enum hrtimer_restart timer_handler(struct hrtimer +					  *handle) +{ +	struct walkera_dev *w; + +	w = container_of(handle, struct walkera_dev, timer); +	w->ack = read_ack(w->pardevice); + +	return HRTIMER_NORESTART; +} + +static int walkera0701_open(struct input_dev *dev) +{ +	struct walkera_dev *w = input_get_drvdata(dev); + +	parport_enable_irq(w->parport); +	return 0; +} + +static void walkera0701_close(struct input_dev *dev) +{ +	struct walkera_dev *w = input_get_drvdata(dev); + +	parport_disable_irq(w->parport); +} + +static int walkera0701_connect(struct walkera_dev *w, int parport) +{ +	int err = -ENODEV; + +	w->parport = parport_find_number(parport); +	if (w->parport == NULL) +		return -ENODEV; + +	if (w->parport->irq == -1) { +		printk(KERN_ERR "walkera0701: parport without interrupt\n"); +		goto init_err; +	} + +	err = -EBUSY; +	w->pardevice = parport_register_device(w->parport, "walkera0701", +				    NULL, NULL, walkera0701_irq_handler, +				    PARPORT_DEV_EXCL, w); +	if (!w->pardevice) +		goto init_err; + +	if (parport_negotiate(w->pardevice->port, IEEE1284_MODE_COMPAT)) +		goto init_err1; + +	if (parport_claim(w->pardevice)) +		goto init_err1; + +	w->input_dev = input_allocate_device(); +	if (!w->input_dev) +		goto init_err2; + +	input_set_drvdata(w->input_dev, w); +	w->input_dev->name = "Walkera WK-0701 TX"; +	w->input_dev->phys = w->parport->name; +	w->input_dev->id.bustype = BUS_PARPORT; + +	/* TODO what id vendor/product/version ? */ +	w->input_dev->id.vendor = 0x0001; +	w->input_dev->id.product = 0x0001; +	w->input_dev->id.version = 0x0100; +	w->input_dev->open = walkera0701_open; +	w->input_dev->close = walkera0701_close; + +	w->input_dev->evbit[0] = BIT(EV_ABS) | BIT_MASK(EV_KEY); +	w->input_dev->keybit[BIT_WORD(BTN_GEAR_DOWN)] = BIT_MASK(BTN_GEAR_DOWN); + +	input_set_abs_params(w->input_dev, ABS_X, -512, 512, 0, 0); +	input_set_abs_params(w->input_dev, ABS_Y, -512, 512, 0, 0); +	input_set_abs_params(w->input_dev, ABS_Z, -512, 512, 0, 0); +	input_set_abs_params(w->input_dev, ABS_THROTTLE, -512, 512, 0, 0); +	input_set_abs_params(w->input_dev, ABS_RUDDER, -512, 512, 0, 0); +	input_set_abs_params(w->input_dev, ABS_MISC, -512, 512, 0, 0); + +	err = input_register_device(w->input_dev); +	if (err) +		goto init_err3; + +	hrtimer_init(&w->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); +	w->timer.function = timer_handler; +	return 0; + + init_err3: +	input_free_device(w->input_dev); + init_err2: +	parport_release(w->pardevice); + init_err1: +	parport_unregister_device(w->pardevice); + init_err: +	parport_put_port(w->parport); +	return err; +} + +static void walkera0701_disconnect(struct walkera_dev *w) +{ +	hrtimer_cancel(&w->timer); +	input_unregister_device(w->input_dev); +	parport_release(w->pardevice); +	parport_unregister_device(w->pardevice); +	parport_put_port(w->parport); +} + +static int __init walkera0701_init(void) +{ +	return walkera0701_connect(&w_dev, walkera0701_pp_no); +} + +static void __exit walkera0701_exit(void) +{ +	walkera0701_disconnect(&w_dev); +} + +module_init(walkera0701_init); +module_exit(walkera0701_exit); diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c index 05f3f43582c..ad67d763fdb 100644 --- a/drivers/input/keyboard/gpio_keys.c +++ b/drivers/input/keyboard/gpio_keys.c @@ -98,6 +98,10 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)  	input->id.product = 0x0001;  	input->id.version = 0x0100; +	/* Enable auto repeat feature of Linux input subsystem */ +	if (pdata->rep) +		__set_bit(EV_REP, input->evbit); +  	ddata->input = input;  	for (i = 0; i < pdata->nbuttons; i++) { diff --git a/drivers/input/keyboard/omap-keypad.c b/drivers/input/keyboard/omap-keypad.c index 69e674ecf19..ec0ebee4606 100644 --- a/drivers/input/keyboard/omap-keypad.c +++ b/drivers/input/keyboard/omap-keypad.c @@ -122,14 +122,10 @@ static void omap_kp_scan_keypad(struct omap_kp *omap_kp, unsigned char *state)  	/* read the keypad status */  	if (cpu_is_omap24xx()) { -		int i; -		for (i = 0; i < omap_kp->rows; i++) -			disable_irq(OMAP_GPIO_IRQ(row_gpios[i])); -  		/* read the keypad status */  		for (col = 0; col < omap_kp->cols; col++) {  			set_col_gpio_val(omap_kp, ~(1 << col)); -			state[col] = ~(get_row_gpio_val(omap_kp)) & 0x3f; +			state[col] = ~(get_row_gpio_val(omap_kp)) & 0xff;  		}  		set_col_gpio_val(omap_kp, 0); diff --git a/drivers/input/misc/pcspkr.c b/drivers/input/misc/pcspkr.c index 43aaa5cebd1..d6a30cee7bc 100644 --- a/drivers/input/misc/pcspkr.c +++ b/drivers/input/misc/pcspkr.c @@ -52,13 +52,13 @@ static int pcspkr_event(struct input_dev *dev, unsigned int type, unsigned int c  	spin_lock_irqsave(&i8253_lock, flags);  	if (count) { -		/* enable counter 2 */ -		outb_p(inb_p(0x61) | 3, 0x61);  		/* set command for counter 2, 2 byte write */  		outb_p(0xB6, 0x43);  		/* select desired HZ */  		outb_p(count & 0xff, 0x42);  		outb((count >> 8) & 0xff, 0x42); +		/* enable counter 2 */ +		outb_p(inb_p(0x61) | 3, 0x61);  	} else {  		/* disable counter 2 */  		outb(inb_p(0x61) & 0xFC, 0x61); diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c index 223d56d5555..46b7caeb281 100644 --- a/drivers/input/misc/uinput.c +++ b/drivers/input/misc/uinput.c @@ -37,6 +37,7 @@  #include <linux/fs.h>  #include <linux/miscdevice.h>  #include <linux/uinput.h> +#include "../input-compat.h"  static int uinput_dev_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)  { @@ -78,6 +79,7 @@ static struct uinput_request* uinput_request_find(struct uinput_device *udev, in  	/* Find an input request, by ID. Returns NULL if the ID isn't valid. */  	if (id >= UINPUT_NUM_REQUESTS || id < 0)  		return NULL; +  	return udev->requests[id];  } @@ -127,6 +129,17 @@ static int uinput_dev_upload_effect(struct input_dev *dev, struct ff_effect *eff  	struct uinput_request request;  	int retval; +	/* +	 * uinput driver does not currently support periodic effects with +	 * custom waveform since it does not have a way to pass buffer of +	 * samples (custom_data) to userspace. If ever there is a device +	 * supporting custom waveforms we would need to define an additional +	 * ioctl (UI_UPLOAD_SAMPLES) but for now we just bail out. +	 */ +	if (effect->type == FF_PERIODIC && +			effect->u.periodic.waveform == FF_CUSTOM) +		return -EINVAL; +  	request.id = -1;  	init_completion(&request.done);  	request.code = UI_FF_UPLOAD; @@ -353,15 +366,15 @@ static inline ssize_t uinput_inject_event(struct uinput_device *udev, const char  {  	struct input_event ev; -	if (count != sizeof(struct input_event)) +	if (count < input_event_size())  		return -EINVAL; -	if (copy_from_user(&ev, buffer, sizeof(struct input_event))) +	if (input_event_from_user(buffer, &ev))  		return -EFAULT;  	input_event(udev->dev, ev.type, ev.code, ev.value); -	return sizeof(struct input_event); +	return input_event_size();  }  static ssize_t uinput_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) @@ -407,13 +420,13 @@ static ssize_t uinput_read(struct file *file, char __user *buffer, size_t count,  		goto out;  	} -	while (udev->head != udev->tail && retval + sizeof(struct input_event) <= count) { -		if (copy_to_user(buffer + retval, &udev->buff[udev->tail], sizeof(struct input_event))) { +	while (udev->head != udev->tail && retval + input_event_size() <= count) { +		if (input_event_to_user(buffer + retval, &udev->buff[udev->tail])) {  			retval = -EFAULT;  			goto out;  		}  		udev->tail = (udev->tail + 1) % UINPUT_BUFFER_SIZE; -		retval += sizeof(struct input_event); +		retval += input_event_size();  	}   out: @@ -444,6 +457,93 @@ static int uinput_release(struct inode *inode, struct file *file)  	return 0;  } +#ifdef CONFIG_COMPAT +struct uinput_ff_upload_compat { +	int			request_id; +	int			retval; +	struct ff_effect_compat	effect; +	struct ff_effect_compat	old; +}; + +static int uinput_ff_upload_to_user(char __user *buffer, +				    const struct uinput_ff_upload *ff_up) +{ +	if (INPUT_COMPAT_TEST) { +		struct uinput_ff_upload_compat ff_up_compat; + +		ff_up_compat.request_id = ff_up->request_id; +		ff_up_compat.retval = ff_up->retval; +		/* +		 * It so happens that the pointer that gives us the trouble +		 * is the last field in the structure. Since we don't support +		 * custom waveforms in uinput anyway we can just copy the whole +		 * thing (to the compat size) and ignore the pointer. +		 */ +		memcpy(&ff_up_compat.effect, &ff_up->effect, +			sizeof(struct ff_effect_compat)); +		memcpy(&ff_up_compat.old, &ff_up->old, +			sizeof(struct ff_effect_compat)); + +		if (copy_to_user(buffer, &ff_up_compat, +				 sizeof(struct uinput_ff_upload_compat))) +			return -EFAULT; +	} else { +		if (copy_to_user(buffer, ff_up, +				 sizeof(struct uinput_ff_upload))) +			return -EFAULT; +	} + +	return 0; +} + +static int uinput_ff_upload_from_user(const char __user *buffer, +				      struct uinput_ff_upload *ff_up) +{ +	if (INPUT_COMPAT_TEST) { +		struct uinput_ff_upload_compat ff_up_compat; + +		if (copy_from_user(&ff_up_compat, buffer, +				   sizeof(struct uinput_ff_upload_compat))) +			return -EFAULT; + +		ff_up->request_id = ff_up_compat.request_id; +		ff_up->retval = ff_up_compat.retval; +		memcpy(&ff_up->effect, &ff_up_compat.effect, +			sizeof(struct ff_effect_compat)); +		memcpy(&ff_up->old, &ff_up_compat.old, +			sizeof(struct ff_effect_compat)); + +	} else { +		if (copy_from_user(ff_up, buffer, +				   sizeof(struct uinput_ff_upload))) +			return -EFAULT; +	} + +	return 0; +} + +#else + +static int uinput_ff_upload_to_user(char __user *buffer, +				    const struct uinput_ff_upload *ff_up) +{ +	if (copy_to_user(buffer, ff_up, sizeof(struct uinput_ff_upload))) +		return -EFAULT; + +	return 0; +} + +static int uinput_ff_upload_from_user(const char __user *buffer, +				      struct uinput_ff_upload *ff_up) +{ +	if (copy_from_user(ff_up, buffer, sizeof(struct uinput_ff_upload))) +		return -EFAULT; + +	return 0; +} + +#endif +  #define uinput_set_bit(_arg, _bit, _max)		\  ({							\  	int __ret = 0;					\ @@ -455,19 +555,17 @@ static int uinput_release(struct inode *inode, struct file *file)  	__ret;						\  }) -static long uinput_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +static long uinput_ioctl_handler(struct file *file, unsigned int cmd, +				 unsigned long arg, void __user *p)  {  	int			retval; -	struct uinput_device	*udev; -	void __user             *p = (void __user *)arg; +	struct uinput_device	*udev = file->private_data;  	struct uinput_ff_upload ff_up;  	struct uinput_ff_erase  ff_erase;  	struct uinput_request   *req;  	int                     length;  	char			*phys; -	udev = file->private_data; -  	retval = mutex_lock_interruptible(&udev->mutex);  	if (retval)  		return retval; @@ -549,26 +647,24 @@ static long uinput_ioctl(struct file *file, unsigned int cmd, unsigned long arg)  			break;  		case UI_BEGIN_FF_UPLOAD: -			if (copy_from_user(&ff_up, p, sizeof(ff_up))) { -				retval = -EFAULT; +			retval = uinput_ff_upload_from_user(p, &ff_up); +			if (retval)  				break; -			} +  			req = uinput_request_find(udev, ff_up.request_id); -			if (!(req && req->code == UI_FF_UPLOAD && req->u.upload.effect)) { +			if (!req || req->code != UI_FF_UPLOAD || !req->u.upload.effect) {  				retval = -EINVAL;  				break;  			} +  			ff_up.retval = 0; -			memcpy(&ff_up.effect, req->u.upload.effect, sizeof(struct ff_effect)); +			ff_up.effect = *req->u.upload.effect;  			if (req->u.upload.old) -				memcpy(&ff_up.old, req->u.upload.old, sizeof(struct ff_effect)); +				ff_up.old = *req->u.upload.old;  			else  				memset(&ff_up.old, 0, sizeof(struct ff_effect)); -			if (copy_to_user(p, &ff_up, sizeof(ff_up))) { -				retval = -EFAULT; -				break; -			} +			retval = uinput_ff_upload_to_user(p, &ff_up);  			break;  		case UI_BEGIN_FF_ERASE: @@ -576,29 +672,34 @@ static long uinput_ioctl(struct file *file, unsigned int cmd, unsigned long arg)  				retval = -EFAULT;  				break;  			} +  			req = uinput_request_find(udev, ff_erase.request_id); -			if (!(req && req->code == UI_FF_ERASE)) { +			if (!req || req->code != UI_FF_ERASE) {  				retval = -EINVAL;  				break;  			} +  			ff_erase.retval = 0;  			ff_erase.effect_id = req->u.effect_id;  			if (copy_to_user(p, &ff_erase, sizeof(ff_erase))) {  				retval = -EFAULT;  				break;  			} +  			break;  		case UI_END_FF_UPLOAD: -			if (copy_from_user(&ff_up, p, sizeof(ff_up))) { -				retval = -EFAULT; +			retval = uinput_ff_upload_from_user(p, &ff_up); +			if (retval)  				break; -			} +  			req = uinput_request_find(udev, ff_up.request_id); -			if (!(req && req->code == UI_FF_UPLOAD && req->u.upload.effect)) { +			if (!req || req->code != UI_FF_UPLOAD || +			    !req->u.upload.effect) {  				retval = -EINVAL;  				break;  			} +  			req->retval = ff_up.retval;  			uinput_request_done(udev, req);  			break; @@ -608,11 +709,13 @@ static long uinput_ioctl(struct file *file, unsigned int cmd, unsigned long arg)  				retval = -EFAULT;  				break;  			} +  			req = uinput_request_find(udev, ff_erase.request_id); -			if (!(req && req->code == UI_FF_ERASE)) { +			if (!req || req->code != UI_FF_ERASE) {  				retval = -EINVAL;  				break;  			} +  			req->retval = ff_erase.retval;  			uinput_request_done(udev, req);  			break; @@ -626,6 +729,18 @@ static long uinput_ioctl(struct file *file, unsigned int cmd, unsigned long arg)  	return retval;  } +static long uinput_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ +	return uinput_ioctl_handler(file, cmd, arg, (void __user *)arg); +} + +#ifdef CONFIG_COMPAT +static long uinput_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ +	return uinput_ioctl_handler(file, cmd, arg, compat_ptr(arg)); +} +#endif +  static const struct file_operations uinput_fops = {  	.owner		= THIS_MODULE,  	.open		= uinput_open, @@ -634,6 +749,9 @@ static const struct file_operations uinput_fops = {  	.write		= uinput_write,  	.poll		= uinput_poll,  	.unlocked_ioctl	= uinput_ioctl, +#ifdef CONFIG_COMPAT +	.compat_ioctl	= uinput_compat_ioctl, +#endif  };  static struct miscdevice uinput_misc = { diff --git a/drivers/input/mouse/appletouch.c b/drivers/input/mouse/appletouch.c index 079816e6b23..454b96112f0 100644 --- a/drivers/input/mouse/appletouch.c +++ b/drivers/input/mouse/appletouch.c @@ -3,7 +3,7 @@   *   * Copyright (C) 2001-2004 Greg Kroah-Hartman (greg@kroah.com)   * Copyright (C) 2005-2008 Johannes Berg (johannes@sipsolutions.net) - * Copyright (C) 2005      Stelian Pop (stelian@popies.net) + * Copyright (C) 2005-2008 Stelian Pop (stelian@popies.net)   * Copyright (C) 2005      Frank Arnold (frank@scirocco-5v-turbo.de)   * Copyright (C) 2005      Peter Osterlund (petero2@telia.com)   * Copyright (C) 2005      Michael Hanselmann (linux-kernel@hansmi.ch) @@ -35,16 +35,74 @@  #include <linux/module.h>  #include <linux/usb/input.h> -/* Type of touchpad */ -enum atp_touchpad_type { -	ATP_FOUNTAIN, -	ATP_GEYSER1, -	ATP_GEYSER2, -	ATP_GEYSER3, -	ATP_GEYSER4 +/* + * Note: We try to keep the touchpad aspect ratio while still doing only + * simple arithmetics: + *	0 <= x <= (xsensors - 1) * xfact + *	0 <= y <= (ysensors - 1) * yfact + */ +struct atp_info { +	int xsensors;				/* number of X sensors */ +	int xsensors_17;			/* 17" models have more sensors */ +	int ysensors;				/* number of Y sensors */ +	int xfact;				/* X multiplication factor */ +	int yfact;				/* Y multiplication factor */ +	int datalen;				/* size of USB transfers */ +	void (*callback)(struct urb *);		/* callback function */ +}; + +static void atp_complete_geyser_1_2(struct urb *urb); +static void atp_complete_geyser_3_4(struct urb *urb); + +static const struct atp_info fountain_info = { +	.xsensors	= 16, +	.xsensors_17	= 26, +	.ysensors	= 16, +	.xfact		= 64, +	.yfact		= 43, +	.datalen	= 81, +	.callback	= atp_complete_geyser_1_2, +}; + +static const struct atp_info geyser1_info = { +	.xsensors	= 16, +	.xsensors_17	= 26, +	.ysensors	= 16, +	.xfact		= 64, +	.yfact		= 43, +	.datalen	= 81, +	.callback	= atp_complete_geyser_1_2, +}; + +static const struct atp_info geyser2_info = { +	.xsensors	= 15, +	.xsensors_17	= 20, +	.ysensors	= 9, +	.xfact		= 64, +	.yfact		= 43, +	.datalen	= 64, +	.callback	= atp_complete_geyser_1_2, +}; + +static const struct atp_info geyser3_info = { +	.xsensors	= 20, +	.ysensors	= 10, +	.xfact		= 64, +	.yfact		= 64, +	.datalen	= 64, +	.callback	= atp_complete_geyser_3_4,  }; -#define ATP_DEVICE(prod, type)					\ +static const struct atp_info geyser4_info = { +	.xsensors	= 20, +	.ysensors	= 10, +	.xfact		= 64, +	.yfact		= 64, +	.datalen	= 64, +	.callback	= atp_complete_geyser_3_4, +}; + +#define ATP_DEVICE(prod, info)					\  {								\  	.match_flags = USB_DEVICE_ID_MATCH_DEVICE |		\  		       USB_DEVICE_ID_MATCH_INT_CLASS |		\ @@ -53,7 +111,7 @@ enum atp_touchpad_type {  	.idProduct = (prod),					\  	.bInterfaceClass = 0x03,				\  	.bInterfaceProtocol = 0x02,				\ -	.driver_info = ATP_ ## type,				\ +	.driver_info = (unsigned long) &info,			\  }  /* @@ -62,43 +120,39 @@ enum atp_touchpad_type {   *  According to Info.plist Geyser IV is the same as Geyser III.)   */ -static struct usb_device_id atp_table [] = { +static struct usb_device_id atp_table[] = {  	/* PowerBooks Feb 2005, iBooks G4 */ -	ATP_DEVICE(0x020e, FOUNTAIN),	/* FOUNTAIN ANSI */ -	ATP_DEVICE(0x020f, FOUNTAIN),	/* FOUNTAIN ISO */ -	ATP_DEVICE(0x030a, FOUNTAIN),	/* FOUNTAIN TP ONLY */ -	ATP_DEVICE(0x030b, GEYSER1),	/* GEYSER 1 TP ONLY */ +	ATP_DEVICE(0x020e, fountain_info),	/* FOUNTAIN ANSI */ +	ATP_DEVICE(0x020f, fountain_info),	/* FOUNTAIN ISO */ +	ATP_DEVICE(0x030a, fountain_info),	/* FOUNTAIN TP ONLY */ +	ATP_DEVICE(0x030b, geyser1_info),	/* GEYSER 1 TP ONLY */  	/* PowerBooks Oct 2005 */ -	ATP_DEVICE(0x0214, GEYSER2),	/* GEYSER 2 ANSI */ -	ATP_DEVICE(0x0215, GEYSER2),	/* GEYSER 2 ISO */ -	ATP_DEVICE(0x0216, GEYSER2),	/* GEYSER 2 JIS */ +	ATP_DEVICE(0x0214, geyser2_info),	/* GEYSER 2 ANSI */ +	ATP_DEVICE(0x0215, geyser2_info),	/* GEYSER 2 ISO */ +	ATP_DEVICE(0x0216, geyser2_info),	/* GEYSER 2 JIS */  	/* Core Duo MacBook & MacBook Pro */ -	ATP_DEVICE(0x0217, GEYSER3),	/* GEYSER 3 ANSI */ -	ATP_DEVICE(0x0218, GEYSER3),	/* GEYSER 3 ISO */ -	ATP_DEVICE(0x0219, GEYSER3),	/* GEYSER 3 JIS */ +	ATP_DEVICE(0x0217, geyser3_info),	/* GEYSER 3 ANSI */ +	ATP_DEVICE(0x0218, geyser3_info),	/* GEYSER 3 ISO */ +	ATP_DEVICE(0x0219, geyser3_info),	/* GEYSER 3 JIS */  	/* Core2 Duo MacBook & MacBook Pro */ -	ATP_DEVICE(0x021a, GEYSER4),	/* GEYSER 4 ANSI */ -	ATP_DEVICE(0x021b, GEYSER4),	/* GEYSER 4 ISO */ -	ATP_DEVICE(0x021c, GEYSER4),	/* GEYSER 4 JIS */ +	ATP_DEVICE(0x021a, geyser4_info),	/* GEYSER 4 ANSI */ +	ATP_DEVICE(0x021b, geyser4_info),	/* GEYSER 4 ISO */ +	ATP_DEVICE(0x021c, geyser4_info),	/* GEYSER 4 JIS */  	/* Core2 Duo MacBook3,1 */ -	ATP_DEVICE(0x0229, GEYSER4),	/* GEYSER 4 HF ANSI */ -	ATP_DEVICE(0x022a, GEYSER4),	/* GEYSER 4 HF ISO */ -	ATP_DEVICE(0x022b, GEYSER4),	/* GEYSER 4 HF JIS */ +	ATP_DEVICE(0x0229, geyser4_info),	/* GEYSER 4 HF ANSI */ +	ATP_DEVICE(0x022a, geyser4_info),	/* GEYSER 4 HF ISO */ +	ATP_DEVICE(0x022b, geyser4_info),	/* GEYSER 4 HF JIS */  	/* Terminating entry */  	{ }  };  MODULE_DEVICE_TABLE(usb, atp_table); -/* - * number of sensors. Note that only 16 instead of 26 X (horizontal) - * sensors exist on 12" and 15" PowerBooks. All models have 16 Y - * (vertical) sensors. - */ +/* maximum number of sensors */  #define ATP_XSENSORS	26  #define ATP_YSENSORS	16 @@ -107,21 +161,6 @@ MODULE_DEVICE_TABLE(usb, atp_table);  /* maximum pressure this driver will report */  #define ATP_PRESSURE	300 -/* - * multiplication factor for the X and Y coordinates. - * We try to keep the touchpad aspect ratio while still doing only simple - * arithmetics. - * The factors below give coordinates like: - * - *      0 <= x <  960 on 12" and 15" Powerbooks - *      0 <= x < 1600 on 17" Powerbooks and 17" MacBook Pro - *      0 <= x < 1216 on MacBooks and 15" MacBook Pro - * - *      0 <= y <  646 on all Powerbooks - *      0 <= y <  774 on all MacBooks - */ -#define ATP_XFACT	64 -#define ATP_YFACT	43  /*   * Threshold for the touchpad sensors. Any change less than ATP_THRESHOLD is @@ -159,7 +198,7 @@ struct atp {  	struct urb		*urb;		/* usb request block */  	u8			*data;		/* transferred data */  	struct input_dev	*input;		/* input dev */ -	enum atp_touchpad_type	type;		/* type of touchpad */ +	const struct atp_info	*info;		/* touchpad model */  	bool			open;  	bool			valid;		/* are the samples valid? */  	bool			size_detect_done; @@ -169,7 +208,6 @@ struct atp {  	signed char		xy_cur[ATP_XSENSORS + ATP_YSENSORS];  	signed char		xy_old[ATP_XSENSORS + ATP_YSENSORS];  	int			xy_acc[ATP_XSENSORS + ATP_YSENSORS]; -	int			datalen;	/* size of USB transfer */  	int			idlecount;	/* number of empty packets */  	struct work_struct	work;  }; @@ -359,7 +397,7 @@ static int atp_status_check(struct urb *urb)  		if (!dev->overflow_warned) {  			printk(KERN_WARNING "appletouch: OVERFLOW with data "  				"length %d, actual length is %d\n", -				dev->datalen, dev->urb->actual_length); +				dev->info->datalen, dev->urb->actual_length);  			dev->overflow_warned = true;  		}  	case -ECONNRESET: @@ -377,7 +415,7 @@ static int atp_status_check(struct urb *urb)  	}  	/* drop incomplete datasets */ -	if (dev->urb->actual_length != dev->datalen) { +	if (dev->urb->actual_length != dev->info->datalen) {  		dprintk("appletouch: incomplete data package"  			" (first byte: %d, length: %d).\n",  			dev->data[0], dev->urb->actual_length); @@ -387,6 +425,25 @@ static int atp_status_check(struct urb *urb)  	return ATP_URB_STATUS_SUCCESS;  } +static void atp_detect_size(struct atp *dev) +{ +	int i; + +	/* 17" Powerbooks have extra X sensors */ +	for (i = dev->info->xsensors; i < ATP_XSENSORS; i++) { +		if (dev->xy_cur[i]) { + +			printk(KERN_INFO "appletouch: 17\" model detected.\n"); + +			input_set_abs_params(dev->input, ABS_X, 0, +					     (dev->info->xsensors_17 - 1) * +							dev->info->xfact - 1, +					     ATP_FUZZ, 0); +			break; +		} +	} +} +  /*   * USB interrupt callback functions   */ @@ -407,7 +464,7 @@ static void atp_complete_geyser_1_2(struct urb *urb)  		goto exit;  	/* reorder the sensors values */ -	if (dev->type == ATP_GEYSER2) { +	if (dev->info == &geyser2_info) {  		memset(dev->xy_cur, 0, sizeof(dev->xy_cur));  		/* @@ -437,8 +494,8 @@ static void atp_complete_geyser_1_2(struct urb *urb)  				dev->xy_cur[i + 24] = dev->data[5 * i + 44];  			/* Y values */ -			dev->xy_cur[i + 26] = dev->data[5 * i +  1]; -			dev->xy_cur[i + 34] = dev->data[5 * i +  3]; +			dev->xy_cur[ATP_XSENSORS + i] = dev->data[5 * i +  1]; +			dev->xy_cur[ATP_XSENSORS + i + 8] = dev->data[5 * i + 3];  		}  	} @@ -453,32 +510,8 @@ static void atp_complete_geyser_1_2(struct urb *urb)  		memcpy(dev->xy_old, dev->xy_cur, sizeof(dev->xy_old));  		/* Perform size detection, if not done already */ -		if (!dev->size_detect_done) { - -			/* 17" Powerbooks have extra X sensors */ -			for (i = (dev->type == ATP_GEYSER2 ? 15 : 16); -			     i < ATP_XSENSORS; i++) { -				if (!dev->xy_cur[i]) -					continue; - -				printk(KERN_INFO -					"appletouch: 17\" model detected.\n"); - -				if (dev->type == ATP_GEYSER2) -					input_set_abs_params(dev->input, ABS_X, -							     0, -							     (20 - 1) * -							     ATP_XFACT - 1, -							     ATP_FUZZ, 0); -				else -					input_set_abs_params(dev->input, ABS_X, -							     0, -							     (26 - 1) * -							     ATP_XFACT - 1, -							     ATP_FUZZ, 0); -				break; -			} - +		if (unlikely(!dev->size_detect_done)) { +			atp_detect_size(dev);  			dev->size_detect_done = 1;  			goto exit;  		} @@ -499,10 +532,10 @@ static void atp_complete_geyser_1_2(struct urb *urb)  	dbg_dump("accumulator", dev->xy_acc);  	x = atp_calculate_abs(dev->xy_acc, ATP_XSENSORS, -			      ATP_XFACT, &x_z, &x_f); +			      dev->info->xfact, &x_z, &x_f);  	y = atp_calculate_abs(dev->xy_acc + ATP_XSENSORS, ATP_YSENSORS, -			      ATP_YFACT, &y_z, &y_f); -	key = dev->data[dev->datalen - 1] & ATP_STATUS_BUTTON; +			      dev->info->yfact, &y_z, &y_f); +	key = dev->data[dev->info->datalen - 1] & ATP_STATUS_BUTTON;  	if (x && y) {  		if (dev->x_old != -1) { @@ -583,7 +616,7 @@ static void atp_complete_geyser_3_4(struct urb *urb)  	dbg_dump("sample", dev->xy_cur);  	/* Just update the base values (i.e. touchpad in untouched state) */ -	if (dev->data[dev->datalen - 1] & ATP_STATUS_BASE_UPDATE) { +	if (dev->data[dev->info->datalen - 1] & ATP_STATUS_BASE_UPDATE) {  		dprintk(KERN_DEBUG "appletouch: updated base values\n"); @@ -610,10 +643,10 @@ static void atp_complete_geyser_3_4(struct urb *urb)  	dbg_dump("accumulator", dev->xy_acc);  	x = atp_calculate_abs(dev->xy_acc, ATP_XSENSORS, -			      ATP_XFACT, &x_z, &x_f); +			      dev->info->xfact, &x_z, &x_f);  	y = atp_calculate_abs(dev->xy_acc + ATP_XSENSORS, ATP_YSENSORS, -			      ATP_YFACT, &y_z, &y_f); -	key = dev->data[dev->datalen - 1] & ATP_STATUS_BUTTON; +			      dev->info->yfact, &y_z, &y_f); +	key = dev->data[dev->info->datalen - 1] & ATP_STATUS_BUTTON;  	if (x && y) {  		if (dev->x_old != -1) { @@ -705,7 +738,7 @@ static int atp_handle_geyser(struct atp *dev)  {  	struct usb_device *udev = dev->udev; -	if (dev->type != ATP_FOUNTAIN) { +	if (dev->info != &fountain_info) {  		/* switch to raw sensor mode */  		if (atp_geyser_init(udev))  			return -EIO; @@ -726,6 +759,7 @@ static int atp_probe(struct usb_interface *iface,  	struct usb_endpoint_descriptor *endpoint;  	int int_in_endpointAddr = 0;  	int i, error = -ENOMEM; +	const struct atp_info *info = (const struct atp_info *)id->driver_info;  	/* set up the endpoint information */  	/* use only the first interrupt-in endpoint */ @@ -753,35 +787,22 @@ static int atp_probe(struct usb_interface *iface,  	dev->udev = udev;  	dev->input = input_dev; -	dev->type = id->driver_info; +	dev->info = info;  	dev->overflow_warned = false; -	if (dev->type == ATP_FOUNTAIN || dev->type == ATP_GEYSER1) -		dev->datalen = 81; -	else -		dev->datalen = 64;  	dev->urb = usb_alloc_urb(0, GFP_KERNEL);  	if (!dev->urb)  		goto err_free_devs; -	dev->data = usb_buffer_alloc(dev->udev, dev->datalen, GFP_KERNEL, +	dev->data = usb_buffer_alloc(dev->udev, dev->info->datalen, GFP_KERNEL,  				     &dev->urb->transfer_dma);  	if (!dev->data)  		goto err_free_urb; -	/* Select the USB complete (callback) function */ -	if (dev->type == ATP_FOUNTAIN || -	    dev->type == ATP_GEYSER1 || -	    dev->type == ATP_GEYSER2) -		usb_fill_int_urb(dev->urb, udev, -				 usb_rcvintpipe(udev, int_in_endpointAddr), -				 dev->data, dev->datalen, -				 atp_complete_geyser_1_2, dev, 1); -	else -		usb_fill_int_urb(dev->urb, udev, -				 usb_rcvintpipe(udev, int_in_endpointAddr), -				 dev->data, dev->datalen, -				 atp_complete_geyser_3_4, dev, 1); +	usb_fill_int_urb(dev->urb, udev, +			 usb_rcvintpipe(udev, int_in_endpointAddr), +			 dev->data, dev->info->datalen, +			 dev->info->callback, dev, 1);  	error = atp_handle_geyser(dev);  	if (error) @@ -802,35 +823,12 @@ static int atp_probe(struct usb_interface *iface,  	set_bit(EV_ABS, input_dev->evbit); -	if (dev->type == ATP_GEYSER3 || dev->type == ATP_GEYSER4) { -		/* -		 * MacBook have 20 X sensors, 10 Y sensors -		 */ -		input_set_abs_params(input_dev, ABS_X, 0, -				     ((20 - 1) * ATP_XFACT) - 1, ATP_FUZZ, 0); -		input_set_abs_params(input_dev, ABS_Y, 0, -				     ((10 - 1) * ATP_YFACT) - 1, ATP_FUZZ, 0); -	} else if (dev->type == ATP_GEYSER2) { -		/* -		 * Oct 2005 15" PowerBooks have 15 X sensors, 17" are detected -		 * later. -		 */ -		input_set_abs_params(input_dev, ABS_X, 0, -				     ((15 - 1) * ATP_XFACT) - 1, ATP_FUZZ, 0); -		input_set_abs_params(input_dev, ABS_Y, 0, -				     ((9 - 1) * ATP_YFACT) - 1, ATP_FUZZ, 0); -	} else { -		/* -		 * 12" and 15" Powerbooks only have 16 x sensors, -		 * 17" models are detected later. -		 */ -		input_set_abs_params(input_dev, ABS_X, 0, -				     (16 - 1) * ATP_XFACT - 1, -				     ATP_FUZZ, 0); -		input_set_abs_params(input_dev, ABS_Y, 0, -				     (ATP_YSENSORS - 1) * ATP_YFACT - 1, -				     ATP_FUZZ, 0); -	} +	input_set_abs_params(input_dev, ABS_X, 0, +			     (dev->info->xsensors - 1) * dev->info->xfact - 1, +			     ATP_FUZZ, 0); +	input_set_abs_params(input_dev, ABS_Y, 0, +			     (dev->info->ysensors - 1) * dev->info->yfact - 1, +			     ATP_FUZZ, 0);  	input_set_abs_params(input_dev, ABS_PRESSURE, 0, ATP_PRESSURE, 0, 0);  	set_bit(EV_KEY, input_dev->evbit); @@ -852,7 +850,7 @@ static int atp_probe(struct usb_interface *iface,  	return 0;   err_free_buffer: -	usb_buffer_free(dev->udev, dev->datalen, +	usb_buffer_free(dev->udev, dev->info->datalen,  			dev->data, dev->urb->transfer_dma);   err_free_urb:  	usb_free_urb(dev->urb); @@ -871,7 +869,7 @@ static void atp_disconnect(struct usb_interface *iface)  	if (dev) {  		usb_kill_urb(dev->urb);  		input_unregister_device(dev->input); -		usb_buffer_free(dev->udev, dev->datalen, +		usb_buffer_free(dev->udev, dev->info->datalen,  				dev->data, dev->urb->transfer_dma);  		usb_free_urb(dev->urb);  		kfree(dev); diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index d349c4a5e3e..865fc69e9bc 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -445,12 +445,14 @@ static void synaptics_process_packet(struct psmouse *psmouse)  	input_report_abs(dev, ABS_TOOL_WIDTH, finger_width);  	input_report_key(dev, BTN_TOOL_FINGER, num_fingers == 1); -	input_report_key(dev, BTN_TOOL_DOUBLETAP, num_fingers == 2); -	input_report_key(dev, BTN_TOOL_TRIPLETAP, num_fingers == 3); -  	input_report_key(dev, BTN_LEFT, hw.left);  	input_report_key(dev, BTN_RIGHT, hw.right); +	if (SYN_CAP_MULTIFINGER(priv->capabilities)) { +		input_report_key(dev, BTN_TOOL_DOUBLETAP, num_fingers == 2); +		input_report_key(dev, BTN_TOOL_TRIPLETAP, num_fingers == 3); +	} +  	if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities))  		input_report_key(dev, BTN_MIDDLE, hw.middle); @@ -543,12 +545,14 @@ static void set_input_params(struct input_dev *dev, struct synaptics_data *priv)  	set_bit(EV_KEY, dev->evbit);  	set_bit(BTN_TOUCH, dev->keybit);  	set_bit(BTN_TOOL_FINGER, dev->keybit); -	set_bit(BTN_TOOL_DOUBLETAP, dev->keybit); -	set_bit(BTN_TOOL_TRIPLETAP, dev->keybit); -  	set_bit(BTN_LEFT, dev->keybit);  	set_bit(BTN_RIGHT, dev->keybit); +	if (SYN_CAP_MULTIFINGER(priv->capabilities)) { +		set_bit(BTN_TOOL_DOUBLETAP, dev->keybit); +		set_bit(BTN_TOOL_TRIPLETAP, dev->keybit); +	} +  	if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities))  		set_bit(BTN_MIDDLE, dev->keybit); diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c index d8c056fe7e9..ef99a7e6d40 100644 --- a/drivers/input/mousedev.c +++ b/drivers/input/mousedev.c @@ -878,8 +878,7 @@ static struct mousedev *mousedev_create(struct input_dev *dev,  	mousedev->handle.handler = handler;  	mousedev->handle.private = mousedev; -	strlcpy(mousedev->dev.bus_id, mousedev->name, -		sizeof(mousedev->dev.bus_id)); +	dev_set_name(&mousedev->dev, mousedev->name);  	mousedev->dev.class = &input_class;  	if (dev)  		mousedev->dev.parent = &dev->dev; diff --git a/drivers/input/serio/libps2.c b/drivers/input/serio/libps2.c index 2b304c22c20..67248c31e19 100644 --- a/drivers/input/serio/libps2.c +++ b/drivers/input/serio/libps2.c @@ -262,9 +262,17 @@ int ps2_handle_ack(struct ps2dev *ps2dev, unsigned char data)  			break;  		case PS2_RET_NAK: -			ps2dev->nak = 1; +			ps2dev->flags |= PS2_FLAG_NAK; +			ps2dev->nak = PS2_RET_NAK;  			break; +		case PS2_RET_ERR: +			if (ps2dev->flags & PS2_FLAG_NAK) { +				ps2dev->flags &= ~PS2_FLAG_NAK; +				ps2dev->nak = PS2_RET_ERR; +				break; +			} +  		/*  		 * Workaround for mice which don't ACK the Get ID command.  		 * These are valid mouse IDs that we recognize. @@ -282,8 +290,11 @@ int ps2_handle_ack(struct ps2dev *ps2dev, unsigned char data)  	} -	if (!ps2dev->nak && ps2dev->cmdcnt) -		ps2dev->flags |= PS2_FLAG_CMD | PS2_FLAG_CMD1; +	if (!ps2dev->nak) { +		ps2dev->flags &= ~PS2_FLAG_NAK; +		if (ps2dev->cmdcnt) +			ps2dev->flags |= PS2_FLAG_CMD | PS2_FLAG_CMD1; +	}  	ps2dev->flags &= ~PS2_FLAG_ACK;  	wake_up(&ps2dev->wait); @@ -329,6 +340,7 @@ void ps2_cmd_aborted(struct ps2dev *ps2dev)  	if (ps2dev->flags & (PS2_FLAG_ACK | PS2_FLAG_CMD))  		wake_up(&ps2dev->wait); -	ps2dev->flags = 0; +	/* reset all flags except last nack */ +	ps2dev->flags &= PS2_FLAG_NAK;  }  EXPORT_SYMBOL(ps2_cmd_aborted); diff --git a/drivers/input/serio/pcips2.c b/drivers/input/serio/pcips2.c index 1b404f9e3bf..1dacbe0d934 100644 --- a/drivers/input/serio/pcips2.c +++ b/drivers/input/serio/pcips2.c @@ -153,7 +153,7 @@ static int __devinit pcips2_probe(struct pci_dev *dev, const struct pci_device_i  	serio->open		= pcips2_open;  	serio->close		= pcips2_close;  	strlcpy(serio->name, pci_name(dev), sizeof(serio->name)); -	strlcpy(serio->phys, dev->dev.bus_id, sizeof(serio->phys)); +	strlcpy(serio->phys, dev_name(&dev->dev), sizeof(serio->phys));  	serio->port_data	= ps2if;  	serio->dev.parent	= &dev->dev;  	ps2if->io		= serio; diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c index 2f12d60eee3..bc033250dfc 100644 --- a/drivers/input/serio/serio.c +++ b/drivers/input/serio/serio.c @@ -546,8 +546,8 @@ static void serio_init_port(struct serio *serio)  	spin_lock_init(&serio->lock);  	mutex_init(&serio->drv_mutex);  	device_initialize(&serio->dev); -	snprintf(serio->dev.bus_id, sizeof(serio->dev.bus_id), -		 "serio%ld", (long)atomic_inc_return(&serio_no) - 1); +	dev_set_name(&serio->dev, "serio%ld", +			(long)atomic_inc_return(&serio_no) - 1);  	serio->dev.bus = &serio_bus;  	serio->dev.release = serio_release_port;  	if (serio->parent) { diff --git a/drivers/input/serio/xilinx_ps2.c b/drivers/input/serio/xilinx_ps2.c index 765007899d9..ebb22f88c84 100644 --- a/drivers/input/serio/xilinx_ps2.c +++ b/drivers/input/serio/xilinx_ps2.c @@ -58,23 +58,20 @@  /* Mask for all the Receive Interrupts */  #define XPS2_IPIXR_RX_ALL	(XPS2_IPIXR_RX_OVF | XPS2_IPIXR_RX_ERR |  \ -					XPS2_IPIXR_RX_FULL) +				 XPS2_IPIXR_RX_FULL)  /* Mask for all the Interrupts */  #define XPS2_IPIXR_ALL		(XPS2_IPIXR_TX_ALL | XPS2_IPIXR_RX_ALL |  \ -					XPS2_IPIXR_WDT_TOUT) +				 XPS2_IPIXR_WDT_TOUT)  /* Global Interrupt Enable mask */  #define XPS2_GIER_GIE_MASK	0x80000000  struct xps2data {  	int irq; -	u32 phys_addr; -	u32 remap_size;  	spinlock_t lock; -	u8 rxb;				/* Rx buffer */  	void __iomem *base_address;	/* virt. address of control registers */ -	unsigned int dfl; +	unsigned int flags;  	struct serio serio;		/* serio */  }; @@ -82,8 +79,13 @@ struct xps2data {  /* XPS PS/2 data transmission calls */  /************************************/ -/* - * xps2_recv() will attempt to receive a byte of data from the PS/2 port. +/** + * xps2_recv() - attempts to receive a byte from the PS/2 port. + * @drvdata:	pointer to ps2 device private data structure + * @byte:	address where the read data will be copied + * + * If there is any data available in the PS/2 receiver, this functions reads + * the data, otherwise it returns error.   */  static int xps2_recv(struct xps2data *drvdata, u8 *byte)  { @@ -116,33 +118,27 @@ static irqreturn_t xps2_interrupt(int irq, void *dev_id)  	/* Check which interrupt is active */  	if (intr_sr & XPS2_IPIXR_RX_OVF) -		printk(KERN_WARNING "%s: receive overrun error\n", -			drvdata->serio.name); +		dev_warn(drvdata->serio.dev.parent, "receive overrun error\n");  	if (intr_sr & XPS2_IPIXR_RX_ERR) -		drvdata->dfl |= SERIO_PARITY; +		drvdata->flags |= SERIO_PARITY;  	if (intr_sr & (XPS2_IPIXR_TX_NOACK | XPS2_IPIXR_WDT_TOUT)) -		drvdata->dfl |= SERIO_TIMEOUT; +		drvdata->flags |= SERIO_TIMEOUT;  	if (intr_sr & XPS2_IPIXR_RX_FULL) { -		status = xps2_recv(drvdata, &drvdata->rxb); +		status = xps2_recv(drvdata, &c);  		/* Error, if a byte is not received */  		if (status) { -			printk(KERN_ERR -				"%s: wrong rcvd byte count (%d)\n", -				drvdata->serio.name, status); +			dev_err(drvdata->serio.dev.parent, +				"wrong rcvd byte count (%d)\n", status);  		} else { -			c = drvdata->rxb; -			serio_interrupt(&drvdata->serio, c, drvdata->dfl); -			drvdata->dfl = 0; +			serio_interrupt(&drvdata->serio, c, drvdata->flags); +			drvdata->flags = 0;  		}  	} -	if (intr_sr & XPS2_IPIXR_TX_ACK) -		drvdata->dfl = 0; -  	return IRQ_HANDLED;  } @@ -150,8 +146,15 @@ static irqreturn_t xps2_interrupt(int irq, void *dev_id)  /* serio callbacks */  /*******************/ -/* - * sxps2_write() sends a byte out through the PS/2 interface. +/** + * sxps2_write() - sends a byte out through the PS/2 port. + * @pserio:	pointer to the serio structure of the PS/2 port + * @c:		data that needs to be written to the PS/2 port + * + * This function checks if the PS/2 transmitter is empty and sends a byte. + * Otherwise it returns error. Transmission fails only when nothing is connected + * to the PS/2 port. Thats why, we do not try to resend the data in case of a + * failure.   */  static int sxps2_write(struct serio *pserio, unsigned char c)  { @@ -174,33 +177,39 @@ static int sxps2_write(struct serio *pserio, unsigned char c)  	return status;  } -/* - * sxps2_open() is called when a port is open by the higher layer. +/** + * sxps2_open() - called when a port is opened by the higher layer. + * @pserio:	pointer to the serio structure of the PS/2 device + * + * This function requests irq and enables interrupts for the PS/2 device.   */  static int sxps2_open(struct serio *pserio)  {  	struct xps2data *drvdata = pserio->port_data; -	int retval; +	int error; +	u8 c; -	retval = request_irq(drvdata->irq, &xps2_interrupt, 0, +	error = request_irq(drvdata->irq, &xps2_interrupt, 0,  				DRIVER_NAME, drvdata); -	if (retval) { -		printk(KERN_ERR -			"%s: Couldn't allocate interrupt %d\n", -			drvdata->serio.name, drvdata->irq); -		return retval; +	if (error) { +		dev_err(drvdata->serio.dev.parent, +			"Couldn't allocate interrupt %d\n", drvdata->irq); +		return error;  	}  	/* start reception by enabling the interrupts */  	out_be32(drvdata->base_address + XPS2_GIER_OFFSET, XPS2_GIER_GIE_MASK);  	out_be32(drvdata->base_address + XPS2_IPIER_OFFSET, XPS2_IPIXR_RX_ALL); -	(void)xps2_recv(drvdata, &drvdata->rxb); +	(void)xps2_recv(drvdata, &c);  	return 0;		/* success */  } -/* - * sxps2_close() frees the interrupt. +/** + * sxps2_close() - frees the interrupt. + * @pserio:	pointer to the serio structure of the PS/2 device + * + * This function frees the irq and disables interrupts for the PS/2 device.   */  static void sxps2_close(struct serio *pserio)  { @@ -212,24 +221,41 @@ static void sxps2_close(struct serio *pserio)  	free_irq(drvdata->irq, drvdata);  } -/*********************/ -/* Device setup code */ -/*********************/ - -static int xps2_setup(struct device *dev, struct resource *regs_res, -		      struct resource *irq_res) +/** + * xps2_of_probe - probe method for the PS/2 device. + * @of_dev:	pointer to OF device structure + * @match:	pointer to the stucture used for matching a device + * + * This function probes the PS/2 device in the device tree. + * It initializes the driver data structure and the hardware. + * It returns 0, if the driver is bound to the PS/2 device, or a negative + * value if there is an error. + */ +static int __devinit xps2_of_probe(struct of_device *ofdev, +				   const struct of_device_id *match)  { +	struct resource r_irq; /* Interrupt resources */ +	struct resource r_mem; /* IO mem resources */  	struct xps2data *drvdata;  	struct serio *serio; -	unsigned long remap_size; -	int retval; +	struct device *dev = &ofdev->dev; +	resource_size_t remap_size, phys_addr; +	int error; + +	dev_info(dev, "Device Tree Probing \'%s\'\n", +			ofdev->node->name); -	if (!dev) -		return -EINVAL; +	/* Get iospace for the device */ +	error = of_address_to_resource(ofdev->node, 0, &r_mem); +	if (error) { +		dev_err(dev, "invalid address\n"); +		return error; +	} -	if (!regs_res || !irq_res) { -		dev_err(dev, "IO resource(s) not found\n"); -		return -EINVAL; +	/* Get IRQ for the device */ +	if (of_irq_to_resource(ofdev->node, 0, &r_irq) == NO_IRQ) { +		dev_err(dev, "no IRQ found\n"); +		return -ENODEV;  	}  	drvdata = kzalloc(sizeof(struct xps2data), GFP_KERNEL); @@ -241,24 +267,23 @@ static int xps2_setup(struct device *dev, struct resource *regs_res,  	dev_set_drvdata(dev, drvdata);  	spin_lock_init(&drvdata->lock); -	drvdata->irq = irq_res->start; +	drvdata->irq = r_irq.start; -	remap_size = regs_res->end - regs_res->start + 1; -	if (!request_mem_region(regs_res->start, remap_size, DRIVER_NAME)) { -		dev_err(dev, "Couldn't lock memory region at 0x%08X\n", -			(unsigned int)regs_res->start); -		retval = -EBUSY; +	phys_addr = r_mem.start; +	remap_size = r_mem.end - r_mem.start + 1; +	if (!request_mem_region(phys_addr, remap_size, DRIVER_NAME)) { +		dev_err(dev, "Couldn't lock memory region at 0x%08llX\n", +			(unsigned long long)phys_addr); +		error = -EBUSY;  		goto failed1;  	}  	/* Fill in configuration data and add them to the list */ -	drvdata->phys_addr = regs_res->start; -	drvdata->remap_size = remap_size; -	drvdata->base_address = ioremap(regs_res->start, remap_size); +	drvdata->base_address = ioremap(phys_addr, remap_size);  	if (drvdata->base_address == NULL) { -		dev_err(dev, "Couldn't ioremap memory at 0x%08X\n", -			(unsigned int)regs_res->start); -		retval = -EFAULT; +		dev_err(dev, "Couldn't ioremap memory at 0x%08llX\n", +			(unsigned long long)phys_addr); +		error = -EFAULT;  		goto failed2;  	} @@ -269,8 +294,9 @@ static int xps2_setup(struct device *dev, struct resource *regs_res,  	 * we have the PS2 in a good state */  	out_be32(drvdata->base_address + XPS2_SRST_OFFSET, XPS2_SRST_RESET); -	dev_info(dev, "Xilinx PS2 at 0x%08X mapped to 0x%p, irq=%d\n", -		drvdata->phys_addr, drvdata->base_address, drvdata->irq); +	dev_info(dev, "Xilinx PS2 at 0x%08llX mapped to 0x%p, irq=%d\n", +		 (unsigned long long)phys_addr, drvdata->base_address, +		 drvdata->irq);  	serio = &drvdata->serio;  	serio->id.type = SERIO_8042; @@ -280,71 +306,51 @@ static int xps2_setup(struct device *dev, struct resource *regs_res,  	serio->port_data = drvdata;  	serio->dev.parent = dev;  	snprintf(serio->name, sizeof(serio->name), -		 "Xilinx XPS PS/2 at %08X", drvdata->phys_addr); +		 "Xilinx XPS PS/2 at %08llX", (unsigned long long)phys_addr);  	snprintf(serio->phys, sizeof(serio->phys), -		 "xilinxps2/serio at %08X", drvdata->phys_addr); +		 "xilinxps2/serio at %08llX", (unsigned long long)phys_addr); +  	serio_register_port(serio);  	return 0;		/* success */  failed2: -	release_mem_region(regs_res->start, remap_size); +	release_mem_region(phys_addr, remap_size);  failed1:  	kfree(drvdata);  	dev_set_drvdata(dev, NULL); -	return retval; -} - -/***************************/ -/* OF Platform Bus Support */ -/***************************/ - -static int __devinit xps2_of_probe(struct of_device *ofdev, const struct -				   of_device_id * match) -{ -	struct resource r_irq; /* Interrupt resources */ -	struct resource r_mem; /* IO mem resources */ -	int rc = 0; - -	printk(KERN_INFO "Device Tree Probing \'%s\'\n", -			ofdev->node->name); - -	/* Get iospace for the device */ -	rc = of_address_to_resource(ofdev->node, 0, &r_mem); -	if (rc) { -		dev_err(&ofdev->dev, "invalid address\n"); -		return rc; -	} - -	/* Get IRQ for the device */ -	rc = of_irq_to_resource(ofdev->node, 0, &r_irq); -	if (rc == NO_IRQ) { -		dev_err(&ofdev->dev, "no IRQ found\n"); -		return rc; -	} - -	return xps2_setup(&ofdev->dev, &r_mem, &r_irq); +	return error;  } +/** + * xps2_of_remove - unbinds the driver from the PS/2 device. + * @of_dev:	pointer to OF device structure + * + * This function is called if a device is physically removed from the system or + * if the driver module is being unloaded. It frees any resources allocated to + * the device. + */  static int __devexit xps2_of_remove(struct of_device *of_dev)  {  	struct device *dev = &of_dev->dev; -	struct xps2data *drvdata; - -	if (!dev) -		return -EINVAL; - -	drvdata = dev_get_drvdata(dev); +	struct xps2data *drvdata = dev_get_drvdata(dev); +	struct resource r_mem; /* IO mem resources */  	serio_unregister_port(&drvdata->serio);  	iounmap(drvdata->base_address); -	release_mem_region(drvdata->phys_addr, drvdata->remap_size); + +	/* Get iospace of the device */ +	if (of_address_to_resource(of_dev->node, 0, &r_mem)) +		dev_err(dev, "invalid address\n"); +	else +		release_mem_region(r_mem.start, r_mem.end - r_mem.start + 1); +  	kfree(drvdata);  	dev_set_drvdata(dev, NULL); -	return 0;		/* success */ +	return 0;  }  /* Match table for of_platform binding */ diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 3d1ab8fa9ac..20eb52ed176 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -95,6 +95,19 @@ config TOUCHSCREEN_ELO  	  To compile this driver as a module, choose M here: the  	  module will be called elo. +config TOUCHSCREEN_WACOM_W8001 +	tristate "Wacom W8001 penabled serial touchscreen" +	select SERIO +	help +	  Say Y here if you have an Wacom W8001 penabled serial touchscreen +	  connected to your system. + +	  If unsure, say N. + +	  To compile this driver as a module, choose M here: the +	  module will be called wacom_w8001. + +  config TOUCHSCREEN_MTOUCH  	tristate "MicroTouch serial touchscreens"  	select SERIO diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 15cf2907948..3dc84d3846c 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -26,6 +26,7 @@ obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213)	+= touchit213.o  obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT)	+= touchright.o  obj-$(CONFIG_TOUCHSCREEN_TOUCHWIN)	+= touchwin.o  obj-$(CONFIG_TOUCHSCREEN_UCB1400)	+= ucb1400_ts.o +obj-$(CONFIG_TOUCHSCREEN_WACOM_W8001)	+= wacom_w8001.o  obj-$(CONFIG_TOUCHSCREEN_WM97XX)	+= wm97xx-ts.o  wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9705)	+= wm9705.o  wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9712)	+= wm9712.o diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c index b9b7fc6ff1e..6017ea6e994 100644 --- a/drivers/input/touchscreen/ads7846.c +++ b/drivers/input/touchscreen/ads7846.c @@ -559,7 +559,7 @@ static void ads7846_rx(void *ads)  	if (packet->tc.ignore || Rt > ts->pressure_max) {  #ifdef VERBOSE  		pr_debug("%s: ignored %d pressure %d\n", -			ts->spi->dev.bus_id, packet->tc.ignore, Rt); +			dev_name(&ts->spi->dev), packet->tc.ignore, Rt);  #endif  		hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_PERIOD),  			      HRTIMER_MODE_REL); @@ -947,7 +947,7 @@ static int __devinit ads7846_probe(struct spi_device *spi)  		ts->penirq_recheck_delay_usecs =  				pdata->penirq_recheck_delay_usecs; -	snprintf(ts->phys, sizeof(ts->phys), "%s/input0", spi->dev.bus_id); +	snprintf(ts->phys, sizeof(ts->phys), "%s/input0", dev_name(&spi->dev));  	input_dev->name = "ADS784x Touchscreen";  	input_dev->phys = ts->phys; diff --git a/drivers/input/touchscreen/usbtouchscreen.c b/drivers/input/touchscreen/usbtouchscreen.c index fdd645c214a..5080b26ba16 100644 --- a/drivers/input/touchscreen/usbtouchscreen.c +++ b/drivers/input/touchscreen/usbtouchscreen.c @@ -424,7 +424,7 @@ static int dmc_tsc10_init(struct usbtouch_usb *usbtouch)  	                      0, 0, buf, 2, USB_CTRL_SET_TIMEOUT);  	if (ret < 0)  		goto err_out; -	if (buf[0] != 0x06 || buf[1] != 0x00) { +	if (buf[0] != 0x06) {  		ret = -ENODEV;  		goto err_out;  	} @@ -437,8 +437,7 @@ static int dmc_tsc10_init(struct usbtouch_usb *usbtouch)  	                      TSC10_RATE_150, 0, buf, 2, USB_CTRL_SET_TIMEOUT);  	if (ret < 0)  		goto err_out; -	if ((buf[0] != 0x06 || buf[1] != 0x00) && -	    (buf[0] != 0x15 || buf[1] != 0x01)) { +	if ((buf[0] != 0x06) && (buf[0] != 0x15 || buf[1] != 0x01)) {  		ret = -ENODEV;  		goto err_out;  	} diff --git a/drivers/input/touchscreen/wacom_w8001.c b/drivers/input/touchscreen/wacom_w8001.c new file mode 100644 index 00000000000..2f33a016764 --- /dev/null +++ b/drivers/input/touchscreen/wacom_w8001.c @@ -0,0 +1,325 @@ +/* + * Wacom W8001 penabled serial touchscreen driver + * + * Copyright (c) 2008 Jaya Kumar + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + * + * Layout based on Elo serial touchscreen driver by Vojtech Pavlik + */ + +#include <linux/errno.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/input.h> +#include <linux/serio.h> +#include <linux/init.h> +#include <linux/ctype.h> + +#define DRIVER_DESC	"Wacom W8001 serial touchscreen driver" + +MODULE_AUTHOR("Jaya Kumar <jayakumar.lkml@gmail.com>"); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); + +/* + * Definitions & global arrays. + */ + +#define W8001_MAX_LENGTH	11 +#define W8001_PACKET_LEN	11 +#define W8001_LEAD_MASK 0x80 +#define W8001_LEAD_BYTE 0x80 +#define W8001_TAB_MASK 0x40 +#define W8001_TAB_BYTE 0x40 + +#define W8001_QUERY_PACKET 0x20 + +struct w8001_coord { +	u8 rdy; +	u8 tsw; +	u8 f1; +	u8 f2; +	u16 x; +	u16 y; +	u16 pen_pressure; +	u8 tilt_x; +	u8 tilt_y; +}; + +/* + * Per-touchscreen data. + */ + +struct w8001 { +	struct input_dev *dev; +	struct serio *serio; +	struct mutex cmd_mutex; +	struct completion cmd_done; +	int id; +	int idx; +	unsigned char expected_packet; +	unsigned char data[W8001_MAX_LENGTH]; +	unsigned char response[W8001_PACKET_LEN]; +	char phys[32]; +}; + +static int parse_data(u8 *data, struct w8001_coord *coord) +{ +	coord->rdy = data[0] & 0x20; +	coord->tsw = data[0] & 0x01; +	coord->f1 = data[0] & 0x02; +	coord->f2 = data[0] & 0x04; + +	coord->x = (data[1] & 0x7F) << 9; +	coord->x |= (data[2] & 0x7F) << 2; +	coord->x |= (data[6] & 0x60) >> 5; + +	coord->y = (data[3] & 0x7F) << 9; +	coord->y |= (data[4] & 0x7F) << 2; +	coord->y |= (data[6] & 0x18) >> 3; + +	coord->pen_pressure = data[5] & 0x7F; +	coord->pen_pressure |= (data[6] & 0x07) << 7 ; + +	coord->tilt_x = data[7] & 0x7F; +	coord->tilt_y = data[8] & 0x7F; + +	return 0; +} + +static void w8001_process_data(struct w8001 *w8001, unsigned char data) +{ +	struct input_dev *dev = w8001->dev; +	u8 tmp; +	struct w8001_coord coord; + +	w8001->data[w8001->idx] = data; +	switch (w8001->idx++) { +	case 0: +		if ((data & W8001_LEAD_MASK) != W8001_LEAD_BYTE) { +			pr_debug("w8001: unsynchronized data: 0x%02x\n", data); +			w8001->idx = 0; +		} +		break; +	case 8: +		tmp = w8001->data[0] & W8001_TAB_MASK; +		if (unlikely(tmp == W8001_TAB_BYTE)) +			break; +		w8001->idx = 0; +		memset(&coord, 0, sizeof(coord)); +		parse_data(w8001->data, &coord); +		input_report_abs(dev, ABS_X, coord.x); +		input_report_abs(dev, ABS_Y, coord.y); +		input_report_abs(dev, ABS_PRESSURE, coord.pen_pressure); +		input_report_key(dev, BTN_TOUCH, coord.tsw); +		input_sync(dev); +		break; +	case 10: +		w8001->idx = 0; +		memcpy(w8001->response, &w8001->data, W8001_PACKET_LEN); +		w8001->expected_packet = W8001_QUERY_PACKET; +		complete(&w8001->cmd_done); +		break; +	} +} + + +static irqreturn_t w8001_interrupt(struct serio *serio, +		unsigned char data, unsigned int flags) +{ +	struct w8001 *w8001 = serio_get_drvdata(serio); + +	w8001_process_data(w8001, data); + +	return IRQ_HANDLED; +} + +static int w8001_async_command(struct w8001 *w8001, unsigned char *packet, +					int len) +{ +	int rc = -1; +	int i; + +	mutex_lock(&w8001->cmd_mutex); + +	for (i = 0; i < len; i++) { +		if (serio_write(w8001->serio, packet[i])) +			goto out; +	} +	rc = 0; + +out: +	mutex_unlock(&w8001->cmd_mutex); +	return rc; +} + +static int w8001_command(struct w8001 *w8001, unsigned char *packet, int len) +{ +	int rc = -1; +	int i; + +	mutex_lock(&w8001->cmd_mutex); + +	serio_pause_rx(w8001->serio); +	init_completion(&w8001->cmd_done); +	serio_continue_rx(w8001->serio); + +	for (i = 0; i < len; i++) { +		if (serio_write(w8001->serio, packet[i])) +			goto out; +	} + +	wait_for_completion_timeout(&w8001->cmd_done, HZ); + +	if (w8001->expected_packet == W8001_QUERY_PACKET) { +		/* We are back in reporting mode, the query was ACKed */ +		memcpy(packet, w8001->response, W8001_PACKET_LEN); +		rc = 0; +	} + +out: +	mutex_unlock(&w8001->cmd_mutex); +	return rc; +} + +static int w8001_setup(struct w8001 *w8001) +{ +	struct w8001_coord coord; +	struct input_dev *dev = w8001->dev; +	unsigned char start[1] = { '1' }; +	unsigned char query[11] = { '*' }; + +	if (w8001_command(w8001, query, 1)) +		return -1; + +	memset(&coord, 0, sizeof(coord)); +	parse_data(query, &coord); + +	input_set_abs_params(dev, ABS_X, 0, coord.x, 0, 0); +	input_set_abs_params(dev, ABS_Y, 0, coord.y, 0, 0); +	input_set_abs_params(dev, ABS_PRESSURE, 0, coord.pen_pressure, 0, 0); +	input_set_abs_params(dev, ABS_TILT_X, 0, coord.tilt_x, 0, 0); +	input_set_abs_params(dev, ABS_TILT_Y, 0, coord.tilt_y, 0, 0); + +	if (w8001_async_command(w8001, start, 1)) +		return -1; + +	return 0; +} + +/* + * w8001_disconnect() is the opposite of w8001_connect() + */ + +static void w8001_disconnect(struct serio *serio) +{ +	struct w8001 *w8001 = serio_get_drvdata(serio); + +	input_get_device(w8001->dev); +	input_unregister_device(w8001->dev); +	serio_close(serio); +	serio_set_drvdata(serio, NULL); +	input_put_device(w8001->dev); +	kfree(w8001); +} + +/* + * w8001_connect() is the routine that is called when someone adds a + * new serio device that supports the w8001 protocol and registers it as + * an input device. + */ + +static int w8001_connect(struct serio *serio, struct serio_driver *drv) +{ +	struct w8001 *w8001; +	struct input_dev *input_dev; +	int err; + +	w8001 = kzalloc(sizeof(struct w8001), GFP_KERNEL); +	input_dev = input_allocate_device(); +	if (!w8001 || !input_dev) { +		err = -ENOMEM; +		goto fail1; +	} + +	w8001->serio = serio; +	w8001->id = serio->id.id; +	w8001->dev = input_dev; +	mutex_init(&w8001->cmd_mutex); +	init_completion(&w8001->cmd_done); +	snprintf(w8001->phys, sizeof(w8001->phys), "%s/input0", serio->phys); + +	input_dev->name = "Wacom W8001 Penabled Serial TouchScreen"; +	input_dev->phys = w8001->phys; +	input_dev->id.bustype = BUS_RS232; +	input_dev->id.vendor = SERIO_W8001; +	input_dev->id.product = w8001->id; +	input_dev->id.version = 0x0100; +	input_dev->dev.parent = &serio->dev; + +	input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); +	input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); + +	serio_set_drvdata(serio, w8001); +	err = serio_open(serio, drv); +	if (err) +		goto fail2; + +	if (w8001_setup(w8001)) +		goto fail3; + +	err = input_register_device(w8001->dev); +	if (err) +		goto fail3; + +	return 0; + +fail3: +	serio_close(serio); +fail2: +	serio_set_drvdata(serio, NULL); +fail1: +	input_free_device(input_dev); +	kfree(w8001); +	return err; +} + +static struct serio_device_id w8001_serio_ids[] = { +	{ +		.type	= SERIO_RS232, +		.proto	= SERIO_W8001, +		.id	= SERIO_ANY, +		.extra	= SERIO_ANY, +	}, +	{ 0 } +}; + +MODULE_DEVICE_TABLE(serio, w8001_serio_ids); + +static struct serio_driver w8001_drv = { +	.driver		= { +		.name	= "w8001", +	}, +	.description	= DRIVER_DESC, +	.id_table	= w8001_serio_ids, +	.interrupt	= w8001_interrupt, +	.connect	= w8001_connect, +	.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); diff --git a/include/linux/gpio_keys.h b/include/linux/gpio_keys.h index ec6ecd74781..1289fa7623c 100644 --- a/include/linux/gpio_keys.h +++ b/include/linux/gpio_keys.h @@ -15,6 +15,7 @@ struct gpio_keys_button {  struct gpio_keys_platform_data {  	struct gpio_keys_button *buttons;  	int nbuttons; +	unsigned int rep:1;		/* enable input subsystem auto repeat */  };  #endif diff --git a/include/linux/libps2.h b/include/linux/libps2.h index afc41336910..b94534b7e26 100644 --- a/include/linux/libps2.h +++ b/include/linux/libps2.h @@ -18,11 +18,13 @@  #define PS2_RET_ID		0x00  #define PS2_RET_ACK		0xfa  #define PS2_RET_NAK		0xfe +#define PS2_RET_ERR		0xfc  #define PS2_FLAG_ACK		1	/* Waiting for ACK/NAK */  #define PS2_FLAG_CMD		2	/* Waiting for command to finish */  #define PS2_FLAG_CMD1		4	/* Waiting for the first byte of command response */  #define PS2_FLAG_WAITID		8	/* Command execiting is GET ID */ +#define PS2_FLAG_NAK		16	/* Last transmission was NAKed */  struct ps2dev {  	struct serio *serio; diff --git a/include/linux/serio.h b/include/linux/serio.h index 25641d9e0ea..1bcb357a01a 100644 --- a/include/linux/serio.h +++ b/include/linux/serio.h @@ -213,5 +213,6 @@ static inline void serio_unpin_driver(struct serio *serio)  #define SERIO_ZHENHUA	0x36  #define SERIO_INEXIO	0x37  #define SERIO_TOUCHIT213	0x37 +#define SERIO_W8001	0x39  #endif  |