Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
Pull input updates from Dmitry Torokhov: - big update to Wacom driver by Benjamin Tissoires, converting it to HID infrastructure and unifying USB and Bluetooth models - large update to ALPS driver by Hans de Goede, which adds support for newer touchpad models as well as cleans up and restructures the code - more changes to Atmel MXT driver, including device tree support - new driver for iPaq x3xxx touchscreen - driver for serial Wacom tablets - driver for Microchip's CAP1106 - assorted cleanups and improvements to existing drover and input core * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input: (93 commits) Input: wacom - update the ABI doc according to latest changes Input: wacom - only register once the MODULE_* macros Input: HID - remove hid-wacom Bluetooth driver Input: wacom - add copyright note and bump version to 2.0 Input: wacom - remove passing id for wacom_set_report Input: wacom - check for bluetooth protocol while setting OLEDs Input: wacom - handle Intuos 4 BT in wacom.ko Input: wacom - handle Graphire BT tablets in wacom.ko Input: wacom - prepare the driver to include BT devices Input: hyperv-keyboard - register as a wakeup source Input: imx_keypad - remove ifdef round PM methods Input: jornada720_ts - get rid of space indentation and use tab Input: jornada720_ts - switch to using managed resources Input: alps - Rushmore and v7 resolution support Input: mcs5000_ts - remove ifdef around power management methods Input: mcs5000_ts - protect PM functions with CONFIG_PM_SLEEP Input: ads7846 - release resources on failure for clean exit Input: wacom - add support for 0x12C ISDv4 sensor Input: atmel_mxt_ts - use deep sleep mode when stopped ARM: dts: am437x-gp-evm: Update binding for touchscreen size ...
This commit is contained in:
		
				commit
				
					
						664fb23070
					
				
			
		
					 48 changed files with 4543 additions and 2913 deletions
				
			
		| 
						 | 
					@ -1,48 +1,27 @@
 | 
				
			||||||
WWhat:		/sys/class/hidraw/hidraw*/device/oled*_img
 | 
					What:		/sys/bus/hid/devices/<bus>:<vid>:<pid>.<n>/speed
 | 
				
			||||||
Date:		June 2012
 | 
					 | 
				
			||||||
Contact:	linux-bluetooth@vger.kernel.org
 | 
					 | 
				
			||||||
Description:
 | 
					 | 
				
			||||||
		The /sys/class/hidraw/hidraw*/device/oled*_img files control
 | 
					 | 
				
			||||||
		OLED mocro displays on Intuos4 Wireless tablet. Accepted image
 | 
					 | 
				
			||||||
		has to contain 256 bytes (64x32 px 1 bit colour). The format
 | 
					 | 
				
			||||||
		is the same as PBM image 62x32px without header (64 bits per
 | 
					 | 
				
			||||||
		horizontal line, 32 lines). An example of setting OLED No. 0:
 | 
					 | 
				
			||||||
		dd bs=256 count=1 if=img_file of=[path to oled0_img]/oled0_img
 | 
					 | 
				
			||||||
		The attribute is read only and no local copy of the image is
 | 
					 | 
				
			||||||
		stored.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
What:		/sys/class/hidraw/hidraw*/device/speed
 | 
					 | 
				
			||||||
Date:		April 2010
 | 
					Date:		April 2010
 | 
				
			||||||
Kernel Version:	2.6.35
 | 
					Kernel Version:	2.6.35
 | 
				
			||||||
Contact:	linux-bluetooth@vger.kernel.org
 | 
					Contact:	linux-bluetooth@vger.kernel.org
 | 
				
			||||||
Description:
 | 
					Description:
 | 
				
			||||||
		The /sys/class/hidraw/hidraw*/device/speed file controls
 | 
							The /sys/bus/hid/devices/<bus>:<vid>:<pid>.<n>/speed file
 | 
				
			||||||
		reporting speed of Wacom bluetooth tablet. Reading from
 | 
							controls reporting speed of Wacom bluetooth tablet. Reading
 | 
				
			||||||
		this file returns 1 if tablet reports in high speed mode
 | 
							from this file returns 1 if tablet reports in high speed mode
 | 
				
			||||||
		or 0 otherwise. Writing to this file one of these values
 | 
							or 0 otherwise. Writing to this file one of these values
 | 
				
			||||||
		switches reporting speed.
 | 
							switches reporting speed.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
What:		/sys/class/leds/0005\:056A\:00BD.0001\:selector\:*/
 | 
					What:		/sys/bus/hid/devices/<bus>:<vid>:<pid>.<n>/wacom_led/led
 | 
				
			||||||
Date:		May 2012
 | 
					Date:		August 2014
 | 
				
			||||||
Kernel Version:	3.5
 | 
					 | 
				
			||||||
Contact:	linux-bluetooth@vger.kernel.org
 | 
					 | 
				
			||||||
Description:
 | 
					 | 
				
			||||||
		LED selector for Intuos4 WL. There are 4 leds, but only one LED
 | 
					 | 
				
			||||||
		can be lit at a time. Max brightness is 127.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
What:		/sys/bus/usb/devices/<busnum>-<devnum>:<cfg>.<intf>/wacom_led/led
 | 
					 | 
				
			||||||
Date:		August 2011
 | 
					 | 
				
			||||||
Contact:	linux-input@vger.kernel.org
 | 
					Contact:	linux-input@vger.kernel.org
 | 
				
			||||||
Description:
 | 
					Description:
 | 
				
			||||||
		Attribute group for control of the status LEDs and the OLEDs.
 | 
							Attribute group for control of the status LEDs and the OLEDs.
 | 
				
			||||||
		This attribute group is only available for Intuos 4 M, L,
 | 
							This attribute group is only available for Intuos 4 M, L,
 | 
				
			||||||
		and XL (with LEDs and OLEDs), Intuos 5 (LEDs only), and Cintiq
 | 
							and XL (with LEDs and OLEDs), Intuos 4 WL, Intuos 5 (LEDs only),
 | 
				
			||||||
		21UX2 and Cintiq 24HD (LEDs only). Therefore its presence
 | 
							Intuos Pro (LEDs only) and Cintiq 21UX2 and Cintiq 24HD
 | 
				
			||||||
		implicitly signifies the presence of said LEDs and OLEDs on the
 | 
							(LEDs only). Therefore its presence implicitly signifies the
 | 
				
			||||||
		tablet device.
 | 
							presence of said LEDs and OLEDs on the tablet device.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
What:		/sys/bus/usb/devices/<busnum>-<devnum>:<cfg>.<intf>/wacom_led/status0_luminance
 | 
					What:		/sys/bus/hid/devices/<bus>:<vid>:<pid>.<n>/wacom_led/status0_luminance
 | 
				
			||||||
Date:		August 2011
 | 
					Date:		August 2014
 | 
				
			||||||
Contact:	linux-input@vger.kernel.org
 | 
					Contact:	linux-input@vger.kernel.org
 | 
				
			||||||
Description:
 | 
					Description:
 | 
				
			||||||
		Writing to this file sets the status LED luminance (1..127)
 | 
							Writing to this file sets the status LED luminance (1..127)
 | 
				
			||||||
| 
						 | 
					@ -50,16 +29,16 @@ Description:
 | 
				
			||||||
		button is pressed on the stylus. This luminance level is
 | 
							button is pressed on the stylus. This luminance level is
 | 
				
			||||||
		normally lower than the level when a button is pressed.
 | 
							normally lower than the level when a button is pressed.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
What:		/sys/bus/usb/devices/<busnum>-<devnum>:<cfg>.<intf>/wacom_led/status1_luminance
 | 
					What:		/sys/bus/hid/devices/<bus>:<vid>:<pid>.<n>/wacom_led/status1_luminance
 | 
				
			||||||
Date:		August 2011
 | 
					Date:		August 2014
 | 
				
			||||||
Contact:	linux-input@vger.kernel.org
 | 
					Contact:	linux-input@vger.kernel.org
 | 
				
			||||||
Description:
 | 
					Description:
 | 
				
			||||||
		Writing to this file sets the status LED luminance (1..127)
 | 
							Writing to this file sets the status LED luminance (1..127)
 | 
				
			||||||
		when the stylus touches the tablet surface, or any button is
 | 
							when the stylus touches the tablet surface, or any button is
 | 
				
			||||||
		pressed on the stylus.
 | 
							pressed on the stylus.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
What:		/sys/bus/usb/devices/<busnum>-<devnum>:<cfg>.<intf>/wacom_led/status_led0_select
 | 
					What:		/sys/bus/hid/devices/<bus>:<vid>:<pid>.<n>/wacom_led/status_led0_select
 | 
				
			||||||
Date:		August 2011
 | 
					Date:		August 2014
 | 
				
			||||||
Contact:	linux-input@vger.kernel.org
 | 
					Contact:	linux-input@vger.kernel.org
 | 
				
			||||||
Description:
 | 
					Description:
 | 
				
			||||||
		Writing to this file sets which one of the four (for Intuos 4
 | 
							Writing to this file sets which one of the four (for Intuos 4
 | 
				
			||||||
| 
						 | 
					@ -67,23 +46,23 @@ Description:
 | 
				
			||||||
		24HD) status LEDs is active (0..3). The other three LEDs on the
 | 
							24HD) status LEDs is active (0..3). The other three LEDs on the
 | 
				
			||||||
		same side are always inactive.
 | 
							same side are always inactive.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
What:		/sys/bus/usb/devices/<busnum>-<devnum>:<cfg>.<intf>/wacom_led/status_led1_select
 | 
					What:		/sys/bus/hid/devices/<bus>:<vid>:<pid>.<n>/wacom_led/status_led1_select
 | 
				
			||||||
Date:		September 2011
 | 
					Date:		August 2014
 | 
				
			||||||
Contact:	linux-input@vger.kernel.org
 | 
					Contact:	linux-input@vger.kernel.org
 | 
				
			||||||
Description:
 | 
					Description:
 | 
				
			||||||
		Writing to this file sets which one of the left four (for Cintiq 21UX2
 | 
							Writing to this file sets which one of the left four (for Cintiq 21UX2
 | 
				
			||||||
		and Cintiq 24HD) status LEDs is active (0..3). The other three LEDs on
 | 
							and Cintiq 24HD) status LEDs is active (0..3). The other three LEDs on
 | 
				
			||||||
		the left are always inactive.
 | 
							the left are always inactive.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
What:		/sys/bus/usb/devices/<busnum>-<devnum>:<cfg>.<intf>/wacom_led/buttons_luminance
 | 
					What:		/sys/bus/hid/devices/<bus>:<vid>:<pid>.<n>/wacom_led/buttons_luminance
 | 
				
			||||||
Date:		August 2011
 | 
					Date:		August 2014
 | 
				
			||||||
Contact:	linux-input@vger.kernel.org
 | 
					Contact:	linux-input@vger.kernel.org
 | 
				
			||||||
Description:
 | 
					Description:
 | 
				
			||||||
		Writing to this file sets the overall luminance level (0..15)
 | 
							Writing to this file sets the overall luminance level (0..15)
 | 
				
			||||||
		of all eight button OLED displays.
 | 
							of all eight button OLED displays.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
What:		/sys/bus/usb/devices/<busnum>-<devnum>:<cfg>.<intf>/wacom_led/button<n>_rawimg
 | 
					What:		/sys/bus/hid/devices/<bus>:<vid>:<pid>.<n>/wacom_led/button<n>_rawimg
 | 
				
			||||||
Date:		August 2011
 | 
					Date:		August 2014
 | 
				
			||||||
Contact:	linux-input@vger.kernel.org
 | 
					Contact:	linux-input@vger.kernel.org
 | 
				
			||||||
Description:
 | 
					Description:
 | 
				
			||||||
		When writing a 1024 byte raw image in Wacom Intuos 4
 | 
							When writing a 1024 byte raw image in Wacom Intuos 4
 | 
				
			||||||
| 
						 | 
					@ -93,3 +72,8 @@ Description:
 | 
				
			||||||
		byte chunk encodes the image data for two consecutive lines on
 | 
							byte chunk encodes the image data for two consecutive lines on
 | 
				
			||||||
		the display. The low nibble of each byte contains the first
 | 
							the display. The low nibble of each byte contains the first
 | 
				
			||||||
		line, and the high nibble contains the second line.
 | 
							line, and the high nibble contains the second line.
 | 
				
			||||||
 | 
							When the Wacom Intuos 4 is connected over Bluetooth, the
 | 
				
			||||||
 | 
							image has to contain 256 bytes (64x32 px 1 bit colour).
 | 
				
			||||||
 | 
							The format is also scrambled, like in the USB mode, and it can
 | 
				
			||||||
 | 
							be summarized by converting 76543210 into GECA6420.
 | 
				
			||||||
 | 
										    HGFEDCBA      HFDB7531
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										25
									
								
								Documentation/devicetree/bindings/input/atmel,maxtouch.txt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								Documentation/devicetree/bindings/input/atmel,maxtouch.txt
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,25 @@
 | 
				
			||||||
 | 
					Atmel maXTouch touchscreen/touchpad
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Required properties:
 | 
				
			||||||
 | 
					- compatible:
 | 
				
			||||||
 | 
					    atmel,maxtouch
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- reg: The I2C address of the device
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- interrupts: The sink for the touchpad's IRQ output
 | 
				
			||||||
 | 
					    See ../interrupt-controller/interrupts.txt
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Optional properties for main touchpad device:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- linux,gpio-keymap: An array of up to 4 entries indicating the Linux
 | 
				
			||||||
 | 
					    keycode generated by each GPIO. Linux keycodes are defined in
 | 
				
			||||||
 | 
					    <dt-bindings/input/input.h>.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Example:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						touch@4b {
 | 
				
			||||||
 | 
							compatible = "atmel,maxtouch";
 | 
				
			||||||
 | 
							reg = <0x4b>;
 | 
				
			||||||
 | 
							interrupt-parent = <&gpio>;
 | 
				
			||||||
 | 
							interrupts = <TEGRA_GPIO(W, 3) IRQ_TYPE_LEVEL_LOW>;
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
							
								
								
									
										53
									
								
								Documentation/devicetree/bindings/input/cap1106.txt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								Documentation/devicetree/bindings/input/cap1106.txt
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,53 @@
 | 
				
			||||||
 | 
					Device tree bindings for Microchip CAP1106, 6 channel capacitive touch sensor
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The node for this driver must be a child of a I2C controller node, as the
 | 
				
			||||||
 | 
					device communication via I2C only.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Required properties:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						compatible:		Must be "microchip,cap1106"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						reg:			The I2C slave address of the device.
 | 
				
			||||||
 | 
									Only 0x28 is valid.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						interrupts:		Property describing the interrupt line the
 | 
				
			||||||
 | 
									device's ALERT#/CM_IRQ# pin is connected to.
 | 
				
			||||||
 | 
									The device only has one interrupt source.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Optional properties:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						autorepeat:		Enables the Linux input system's autorepeat
 | 
				
			||||||
 | 
									feature on the input device.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						microchip,sensor-gain:	Defines the gain of the sensor circuitry. This
 | 
				
			||||||
 | 
									effectively controls the sensitivity, as a
 | 
				
			||||||
 | 
									smaller delta capacitance is required to
 | 
				
			||||||
 | 
									generate the same delta count values.
 | 
				
			||||||
 | 
									Valid values are 1, 2, 4, and 8.
 | 
				
			||||||
 | 
									By default, a gain of 1 is set.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						linux,keycodes:		Specifies an array of numeric keycode values to
 | 
				
			||||||
 | 
									be used for the channels. If this property is
 | 
				
			||||||
 | 
									omitted, KEY_A, KEY_B, etc are used as
 | 
				
			||||||
 | 
									defaults. The array must have exactly six
 | 
				
			||||||
 | 
									entries.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Example:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					i2c_controller {
 | 
				
			||||||
 | 
						cap1106@28 {
 | 
				
			||||||
 | 
							compatible = "microchip,cap1106";
 | 
				
			||||||
 | 
							interrupt-parent = <&gpio1>;
 | 
				
			||||||
 | 
							interrupts = <0 0>;
 | 
				
			||||||
 | 
							reg = <0x28>;
 | 
				
			||||||
 | 
							autorepeat;
 | 
				
			||||||
 | 
							microchip,sensor-gain = <2>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							linux,keycodes = <103		/* KEY_UP */
 | 
				
			||||||
 | 
									  106		/* KEY_RIGHT */
 | 
				
			||||||
 | 
									  108		/* KEY_DOWN */
 | 
				
			||||||
 | 
									  105		/* KEY_LEFT */
 | 
				
			||||||
 | 
									  109		/* KEY_PAGEDOWN */
 | 
				
			||||||
 | 
									  104>;		/* KEY_PAGEUP */
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,26 @@
 | 
				
			||||||
 | 
					* Pixcir I2C touchscreen controllers
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Required properties:
 | 
				
			||||||
 | 
					- compatible: must be "pixcir,pixcir_ts" or "pixcir,pixcir_tangoc"
 | 
				
			||||||
 | 
					- reg: I2C address of the chip
 | 
				
			||||||
 | 
					- interrupts: interrupt to which the chip is connected
 | 
				
			||||||
 | 
					- attb-gpio: GPIO connected to the ATTB line of the chip
 | 
				
			||||||
 | 
					- touchscreen-size-x: horizontal resolution of touchscreen (in pixels)
 | 
				
			||||||
 | 
					- touchscreen-size-y: vertical resolution of touchscreen (in pixels)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Example:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						i2c@00000000 {
 | 
				
			||||||
 | 
							/* ... */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							pixcir_ts@5c {
 | 
				
			||||||
 | 
								compatible = "pixcir,pixcir_ts";
 | 
				
			||||||
 | 
								reg = <0x5c>;
 | 
				
			||||||
 | 
								interrupts = <2 0>;
 | 
				
			||||||
 | 
								attb-gpio = <&gpf 2 0 2>;
 | 
				
			||||||
 | 
								touchscreen-size-x = <800>;
 | 
				
			||||||
 | 
								touchscreen-size-y = <600>;
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* ... */
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
| 
						 | 
					@ -9,6 +9,9 @@ Required properties:
 | 
				
			||||||
- x-size: horizontal resolution of touchscreen
 | 
					- x-size: horizontal resolution of touchscreen
 | 
				
			||||||
- y-size: vertical resolution of touchscreen
 | 
					- y-size: vertical resolution of touchscreen
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Optional properties:
 | 
				
			||||||
 | 
					- vdd-supply: Regulator controlling the controller supply
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Example:
 | 
					Example:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	i2c@00000000 {
 | 
						i2c@00000000 {
 | 
				
			||||||
| 
						 | 
					@ -18,6 +21,7 @@ Example:
 | 
				
			||||||
			compatible = "neonode,zforce";
 | 
								compatible = "neonode,zforce";
 | 
				
			||||||
			reg = <0x50>;
 | 
								reg = <0x50>;
 | 
				
			||||||
			interrupts = <2 0>;
 | 
								interrupts = <2 0>;
 | 
				
			||||||
 | 
								vdd-supply = <®_zforce_vdd>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			gpios = <&gpio5 6 0>, /* INT */
 | 
								gpios = <&gpio5 6 0>, /* INT */
 | 
				
			||||||
				<&gpio5 9 0>; /* RST */
 | 
									<&gpio5 9 0>; /* RST */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -103,6 +103,7 @@ panasonic	Panasonic Corporation
 | 
				
			||||||
phytec	PHYTEC Messtechnik GmbH
 | 
					phytec	PHYTEC Messtechnik GmbH
 | 
				
			||||||
picochip	Picochip Ltd
 | 
					picochip	Picochip Ltd
 | 
				
			||||||
plathome	Plat'Home Co., Ltd.
 | 
					plathome	Plat'Home Co., Ltd.
 | 
				
			||||||
 | 
					pixcir  PIXCIR MICROELECTRONICS Co., Ltd
 | 
				
			||||||
powervr	PowerVR (deprecated, use img)
 | 
					powervr	PowerVR (deprecated, use img)
 | 
				
			||||||
qca	Qualcomm Atheros, Inc.
 | 
					qca	Qualcomm Atheros, Inc.
 | 
				
			||||||
qcom	Qualcomm Technologies, Inc
 | 
					qcom	Qualcomm Technologies, Inc
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -9877,6 +9877,13 @@ M:	Pierre Ossman <pierre@ossman.eu>
 | 
				
			||||||
S:	Maintained
 | 
					S:	Maintained
 | 
				
			||||||
F:	drivers/mmc/host/wbsd.*
 | 
					F:	drivers/mmc/host/wbsd.*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					WACOM PROTOCOL 4 SERIAL TABLETS
 | 
				
			||||||
 | 
					M:	Julian Squires <julian@cipht.net>
 | 
				
			||||||
 | 
					M:	Hans de Goede <hdegoede@redhat.com>
 | 
				
			||||||
 | 
					L:	linux-input@vger.kernel.org
 | 
				
			||||||
 | 
					S:	Maintained
 | 
				
			||||||
 | 
					F:	drivers/input/tablet/wacom_serial4.c
 | 
				
			||||||
 | 
					
 | 
				
			||||||
WATCHDOG DEVICE DRIVERS
 | 
					WATCHDOG DEVICE DRIVERS
 | 
				
			||||||
M:	Wim Van Sebroeck <wim@iguana.be>
 | 
					M:	Wim Van Sebroeck <wim@iguana.be>
 | 
				
			||||||
L:	linux-watchdog@vger.kernel.org
 | 
					L:	linux-watchdog@vger.kernel.org
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -334,8 +334,8 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		attb-gpio = <&gpio3 22 GPIO_ACTIVE_HIGH>;
 | 
							attb-gpio = <&gpio3 22 GPIO_ACTIVE_HIGH>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		x-size = <1024>;
 | 
							touchscreen-size-x = <1024>;
 | 
				
			||||||
		y-size = <600>;
 | 
							touchscreen-size-y = <600>;
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -403,8 +403,8 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		attb-gpio = <&gpio1 17 GPIO_ACTIVE_HIGH>;
 | 
							attb-gpio = <&gpio1 17 GPIO_ACTIVE_HIGH>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		x-size = <1024>;
 | 
							touchscreen-size-x = <1024>;
 | 
				
			||||||
		y-size = <600>;
 | 
							touchscreen-size-y = <600>;
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -764,12 +764,17 @@ config THRUSTMASTER_FF
 | 
				
			||||||
	  Rumble Force or Force Feedback Wheel.
 | 
						  Rumble Force or Force Feedback Wheel.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
config HID_WACOM
 | 
					config HID_WACOM
 | 
				
			||||||
	tristate "Wacom Bluetooth devices support"
 | 
						tristate "Wacom Intuos/Graphire tablet support (USB)"
 | 
				
			||||||
	depends on HID
 | 
						depends on HID
 | 
				
			||||||
	depends on LEDS_CLASS
 | 
					 | 
				
			||||||
	select POWER_SUPPLY
 | 
						select POWER_SUPPLY
 | 
				
			||||||
	---help---
 | 
						select NEW_LEDS
 | 
				
			||||||
	Support for Wacom Graphire Bluetooth and Intuos4 WL tablets.
 | 
						select LEDS_CLASS
 | 
				
			||||||
 | 
						help
 | 
				
			||||||
 | 
						  Say Y here if you want to use the USB or BT version of the Wacom Intuos
 | 
				
			||||||
 | 
						  or Graphire tablet.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						  To compile this driver as a module, choose M here: the
 | 
				
			||||||
 | 
						  module will be called wacom.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
config HID_WIIMOTE
 | 
					config HID_WIIMOTE
 | 
				
			||||||
	tristate "Nintendo Wii / Wii U peripherals"
 | 
						tristate "Nintendo Wii / Wii U peripherals"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -116,7 +116,9 @@ obj-$(CONFIG_HID_UCLOGIC)	+= hid-uclogic.o
 | 
				
			||||||
obj-$(CONFIG_HID_XINMO)		+= hid-xinmo.o
 | 
					obj-$(CONFIG_HID_XINMO)		+= hid-xinmo.o
 | 
				
			||||||
obj-$(CONFIG_HID_ZEROPLUS)	+= hid-zpff.o
 | 
					obj-$(CONFIG_HID_ZEROPLUS)	+= hid-zpff.o
 | 
				
			||||||
obj-$(CONFIG_HID_ZYDACRON)	+= hid-zydacron.o
 | 
					obj-$(CONFIG_HID_ZYDACRON)	+= hid-zydacron.o
 | 
				
			||||||
obj-$(CONFIG_HID_WACOM)		+= hid-wacom.o
 | 
					
 | 
				
			||||||
 | 
					wacom-objs			:= wacom_wac.o wacom_sys.o
 | 
				
			||||||
 | 
					obj-$(CONFIG_HID_WACOM)		+= wacom.o
 | 
				
			||||||
obj-$(CONFIG_HID_WALTOP)	+= hid-waltop.o
 | 
					obj-$(CONFIG_HID_WALTOP)	+= hid-waltop.o
 | 
				
			||||||
obj-$(CONFIG_HID_WIIMOTE)	+= hid-wiimote.o
 | 
					obj-$(CONFIG_HID_WIIMOTE)	+= hid-wiimote.o
 | 
				
			||||||
obj-$(CONFIG_HID_SENSOR_HUB)	+= hid-sensor-hub.o
 | 
					obj-$(CONFIG_HID_SENSOR_HUB)	+= hid-sensor-hub.o
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -789,6 +789,15 @@ static int hid_scan_report(struct hid_device *hid)
 | 
				
			||||||
		/* hid-rmi should take care of them, not hid-generic */
 | 
							/* hid-rmi should take care of them, not hid-generic */
 | 
				
			||||||
		hid->group = HID_GROUP_RMI;
 | 
							hid->group = HID_GROUP_RMI;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * Vendor specific handlings
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						switch (hid->vendor) {
 | 
				
			||||||
 | 
						case USB_VENDOR_ID_WACOM:
 | 
				
			||||||
 | 
							hid->group = HID_GROUP_WACOM;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	vfree(parser);
 | 
						vfree(parser);
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1938,8 +1947,6 @@ static const struct hid_device_id hid_have_special_driver[] = {
 | 
				
			||||||
	{ HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP_LTD, USB_DEVICE_ID_SUPER_JOY_BOX_3_PRO) },
 | 
						{ HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP_LTD, USB_DEVICE_ID_SUPER_JOY_BOX_3_PRO) },
 | 
				
			||||||
	{ HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP_LTD, USB_DEVICE_ID_SUPER_DUAL_BOX_PRO) },
 | 
						{ HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP_LTD, USB_DEVICE_ID_SUPER_DUAL_BOX_PRO) },
 | 
				
			||||||
	{ HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP_LTD, USB_DEVICE_ID_SUPER_JOY_BOX_5_PRO) },
 | 
						{ HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP_LTD, USB_DEVICE_ID_SUPER_JOY_BOX_5_PRO) },
 | 
				
			||||||
	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH) },
 | 
					 | 
				
			||||||
	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS4_BLUETOOTH) },
 | 
					 | 
				
			||||||
	{ HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_SLIM_TABLET_5_8_INCH) },
 | 
						{ HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_SLIM_TABLET_5_8_INCH) },
 | 
				
			||||||
	{ HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_SLIM_TABLET_12_1_INCH) },
 | 
						{ HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_SLIM_TABLET_12_1_INCH) },
 | 
				
			||||||
	{ HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_Q_PAD) },
 | 
						{ HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_Q_PAD) },
 | 
				
			||||||
| 
						 | 
					@ -2345,7 +2352,6 @@ static const struct hid_device_id hid_ignore_list[] = {
 | 
				
			||||||
	{ HID_USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_SKIP) },
 | 
						{ HID_USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_SKIP) },
 | 
				
			||||||
	{ HID_USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_CYCLOPS) },
 | 
						{ HID_USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_CYCLOPS) },
 | 
				
			||||||
	{ HID_USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_LCSPEC) },
 | 
						{ HID_USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_LCSPEC) },
 | 
				
			||||||
	{ HID_USB_DEVICE(USB_VENDOR_ID_WACOM, HID_ANY_ID) },
 | 
					 | 
				
			||||||
	{ HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_4_PHIDGETSERVO_20) },
 | 
						{ HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_4_PHIDGETSERVO_20) },
 | 
				
			||||||
	{ HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_1_PHIDGETSERVO_20) },
 | 
						{ HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_1_PHIDGETSERVO_20) },
 | 
				
			||||||
	{ HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_8_8_4_IF_KIT) },
 | 
						{ HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_8_8_4_IF_KIT) },
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,973 +0,0 @@
 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
 *  Bluetooth Wacom Tablet support
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 *  Copyright (c) 1999 Andreas Gal
 | 
					 | 
				
			||||||
 *  Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
 | 
					 | 
				
			||||||
 *  Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
 | 
					 | 
				
			||||||
 *  Copyright (c) 2006-2007 Jiri Kosina
 | 
					 | 
				
			||||||
 *  Copyright (c) 2008 Jiri Slaby <jirislaby@gmail.com>
 | 
					 | 
				
			||||||
 *  Copyright (c) 2006 Andrew Zabolotny <zap@homelink.ru>
 | 
					 | 
				
			||||||
 *  Copyright (c) 2009 Bastien Nocera <hadess@hadess.net>
 | 
					 | 
				
			||||||
 *  Copyright (c) 2011 Przemysław Firszt <przemo@firszt.eu>
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
 * 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.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <linux/device.h>
 | 
					 | 
				
			||||||
#include <linux/hid.h>
 | 
					 | 
				
			||||||
#include <linux/module.h>
 | 
					 | 
				
			||||||
#include <linux/leds.h>
 | 
					 | 
				
			||||||
#include <linux/slab.h>
 | 
					 | 
				
			||||||
#include <linux/power_supply.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "hid-ids.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define PAD_DEVICE_ID	0x0F
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define WAC_CMD_LED_CONTROL     0x20
 | 
					 | 
				
			||||||
#define WAC_CMD_ICON_START_STOP     0x21
 | 
					 | 
				
			||||||
#define WAC_CMD_ICON_TRANSFER       0x26
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct wacom_data {
 | 
					 | 
				
			||||||
	__u16 tool;
 | 
					 | 
				
			||||||
	__u16 butstate;
 | 
					 | 
				
			||||||
	__u8 whlstate;
 | 
					 | 
				
			||||||
	__u8 features;
 | 
					 | 
				
			||||||
	__u32 id;
 | 
					 | 
				
			||||||
	__u32 serial;
 | 
					 | 
				
			||||||
	unsigned char high_speed;
 | 
					 | 
				
			||||||
	__u8 battery_capacity;
 | 
					 | 
				
			||||||
	__u8 power_raw;
 | 
					 | 
				
			||||||
	__u8 ps_connected;
 | 
					 | 
				
			||||||
	__u8 bat_charging;
 | 
					 | 
				
			||||||
	struct power_supply battery;
 | 
					 | 
				
			||||||
	struct power_supply ac;
 | 
					 | 
				
			||||||
	__u8 led_selector;
 | 
					 | 
				
			||||||
	struct led_classdev *leds[4];
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*percent of battery capacity for Graphire
 | 
					 | 
				
			||||||
  8th value means AC online and show 100% capacity */
 | 
					 | 
				
			||||||
static unsigned short batcap_gr[8] = { 1, 15, 25, 35, 50, 70, 100, 100 };
 | 
					 | 
				
			||||||
/*percent of battery capacity for Intuos4 WL, AC has a separate bit*/
 | 
					 | 
				
			||||||
static unsigned short batcap_i4[8] = { 1, 15, 30, 45, 60, 70, 85, 100 };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static enum power_supply_property wacom_battery_props[] = {
 | 
					 | 
				
			||||||
	POWER_SUPPLY_PROP_PRESENT,
 | 
					 | 
				
			||||||
	POWER_SUPPLY_PROP_CAPACITY,
 | 
					 | 
				
			||||||
	POWER_SUPPLY_PROP_SCOPE,
 | 
					 | 
				
			||||||
	POWER_SUPPLY_PROP_STATUS,
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static enum power_supply_property wacom_ac_props[] = {
 | 
					 | 
				
			||||||
	POWER_SUPPLY_PROP_PRESENT,
 | 
					 | 
				
			||||||
	POWER_SUPPLY_PROP_ONLINE,
 | 
					 | 
				
			||||||
	POWER_SUPPLY_PROP_SCOPE,
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void wacom_scramble(__u8 *image)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	__u16 mask;
 | 
					 | 
				
			||||||
	__u16 s1;
 | 
					 | 
				
			||||||
	__u16 s2;
 | 
					 | 
				
			||||||
	__u16 r1 ;
 | 
					 | 
				
			||||||
	__u16 r2 ;
 | 
					 | 
				
			||||||
	__u16 r;
 | 
					 | 
				
			||||||
	__u8 buf[256];
 | 
					 | 
				
			||||||
	int i, w, x, y, z;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for (x = 0; x < 32; x++) {
 | 
					 | 
				
			||||||
		for (y = 0; y < 8; y++)
 | 
					 | 
				
			||||||
			buf[(8 * x) + (7 - y)] = image[(8 * x) + y];
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Change 76543210 into GECA6420 as required by Intuos4 WL
 | 
					 | 
				
			||||||
	 *        HGFEDCBA      HFDB7531
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	for (x = 0; x < 4; x++) {
 | 
					 | 
				
			||||||
		for (y = 0; y < 4; y++) {
 | 
					 | 
				
			||||||
			for (z = 0; z < 8; z++) {
 | 
					 | 
				
			||||||
				mask = 0x0001;
 | 
					 | 
				
			||||||
				r1 = 0;
 | 
					 | 
				
			||||||
				r2 = 0;
 | 
					 | 
				
			||||||
				i = (x << 6) + (y << 4) + z;
 | 
					 | 
				
			||||||
				s1 = buf[i];
 | 
					 | 
				
			||||||
				s2 = buf[i+8];
 | 
					 | 
				
			||||||
				for (w = 0; w < 8; w++) {
 | 
					 | 
				
			||||||
					r1 |= (s1 & mask);
 | 
					 | 
				
			||||||
					r2 |= (s2 & mask);
 | 
					 | 
				
			||||||
					s1 <<= 1;
 | 
					 | 
				
			||||||
					s2 <<= 1;
 | 
					 | 
				
			||||||
					mask <<= 2;
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
				r = r1 | (r2 << 1);
 | 
					 | 
				
			||||||
				i = (x << 6) + (y << 4) + (z << 1);
 | 
					 | 
				
			||||||
				image[i] = 0xFF & r;
 | 
					 | 
				
			||||||
				image[i+1] = (0xFF00 & r) >> 8;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void wacom_set_image(struct hid_device *hdev, const char *image,
 | 
					 | 
				
			||||||
						__u8 icon_no)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	__u8 rep_data[68];
 | 
					 | 
				
			||||||
	__u8 p[256];
 | 
					 | 
				
			||||||
	int ret, i, j;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for (i = 0; i < 256; i++)
 | 
					 | 
				
			||||||
		p[i] = image[i];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	rep_data[0] = WAC_CMD_ICON_START_STOP;
 | 
					 | 
				
			||||||
	rep_data[1] = 0;
 | 
					 | 
				
			||||||
	ret = hid_hw_raw_request(hdev, rep_data[0], rep_data, 2,
 | 
					 | 
				
			||||||
				 HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
 | 
					 | 
				
			||||||
	if (ret < 0)
 | 
					 | 
				
			||||||
		goto err;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	rep_data[0] = WAC_CMD_ICON_TRANSFER;
 | 
					 | 
				
			||||||
	rep_data[1] = icon_no & 0x07;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	wacom_scramble(p);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for (i = 0; i < 4; i++) {
 | 
					 | 
				
			||||||
		for (j = 0; j < 64; j++)
 | 
					 | 
				
			||||||
			rep_data[j + 3] = p[(i << 6) + j];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		rep_data[2] = i;
 | 
					 | 
				
			||||||
		ret = hid_hw_raw_request(hdev, rep_data[0], rep_data, 67,
 | 
					 | 
				
			||||||
					HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	rep_data[0] = WAC_CMD_ICON_START_STOP;
 | 
					 | 
				
			||||||
	rep_data[1] = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ret = hid_hw_raw_request(hdev, rep_data[0], rep_data, 2,
 | 
					 | 
				
			||||||
				 HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
err:
 | 
					 | 
				
			||||||
	return;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void wacom_leds_set_brightness(struct led_classdev *led_dev,
 | 
					 | 
				
			||||||
						enum led_brightness value)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct device *dev = led_dev->dev->parent;
 | 
					 | 
				
			||||||
	struct hid_device *hdev;
 | 
					 | 
				
			||||||
	struct wacom_data *wdata;
 | 
					 | 
				
			||||||
	unsigned char *buf;
 | 
					 | 
				
			||||||
	__u8 led = 0;
 | 
					 | 
				
			||||||
	int i;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	hdev = container_of(dev, struct hid_device, dev);
 | 
					 | 
				
			||||||
	wdata = hid_get_drvdata(hdev);
 | 
					 | 
				
			||||||
	for (i = 0; i < 4; ++i) {
 | 
					 | 
				
			||||||
		if (wdata->leds[i] == led_dev)
 | 
					 | 
				
			||||||
			wdata->led_selector = i;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	led = wdata->led_selector | 0x04;
 | 
					 | 
				
			||||||
	buf = kzalloc(9, GFP_KERNEL);
 | 
					 | 
				
			||||||
	if (buf) {
 | 
					 | 
				
			||||||
		buf[0] = WAC_CMD_LED_CONTROL;
 | 
					 | 
				
			||||||
		buf[1] = led;
 | 
					 | 
				
			||||||
		buf[2] = value >> 2;
 | 
					 | 
				
			||||||
		buf[3] = value;
 | 
					 | 
				
			||||||
		/* use fixed brightness for OLEDs */
 | 
					 | 
				
			||||||
		buf[4] = 0x08;
 | 
					 | 
				
			||||||
		hid_hw_raw_request(hdev, buf[0], buf, 9, HID_FEATURE_REPORT,
 | 
					 | 
				
			||||||
				   HID_REQ_SET_REPORT);
 | 
					 | 
				
			||||||
		kfree(buf);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static enum led_brightness wacom_leds_get_brightness(struct led_classdev *led_dev)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct wacom_data *wdata;
 | 
					 | 
				
			||||||
	struct device *dev = led_dev->dev->parent;
 | 
					 | 
				
			||||||
	int value = 0;
 | 
					 | 
				
			||||||
	int i;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	wdata = hid_get_drvdata(container_of(dev, struct hid_device, dev));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for (i = 0; i < 4; ++i) {
 | 
					 | 
				
			||||||
		if (wdata->leds[i] == led_dev) {
 | 
					 | 
				
			||||||
			value = wdata->leds[i]->brightness;
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return value;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int wacom_initialize_leds(struct hid_device *hdev)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct wacom_data *wdata = hid_get_drvdata(hdev);
 | 
					 | 
				
			||||||
	struct led_classdev *led;
 | 
					 | 
				
			||||||
	struct device *dev = &hdev->dev;
 | 
					 | 
				
			||||||
	size_t namesz = strlen(dev_name(dev)) + 12;
 | 
					 | 
				
			||||||
	char *name;
 | 
					 | 
				
			||||||
	int i, ret;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	wdata->led_selector = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for (i = 0; i < 4; i++) {
 | 
					 | 
				
			||||||
		led = kzalloc(sizeof(struct led_classdev) + namesz, GFP_KERNEL);
 | 
					 | 
				
			||||||
		if (!led) {
 | 
					 | 
				
			||||||
			hid_warn(hdev,
 | 
					 | 
				
			||||||
				 "can't allocate memory for LED selector\n");
 | 
					 | 
				
			||||||
			ret = -ENOMEM;
 | 
					 | 
				
			||||||
			goto err;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		name = (void *)&led[1];
 | 
					 | 
				
			||||||
		snprintf(name, namesz, "%s:selector:%d", dev_name(dev), i);
 | 
					 | 
				
			||||||
		led->name = name;
 | 
					 | 
				
			||||||
		led->brightness = 0;
 | 
					 | 
				
			||||||
		led->max_brightness = 127;
 | 
					 | 
				
			||||||
		led->brightness_get = wacom_leds_get_brightness;
 | 
					 | 
				
			||||||
		led->brightness_set = wacom_leds_set_brightness;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		wdata->leds[i] = led;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		ret = led_classdev_register(dev, wdata->leds[i]);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (ret) {
 | 
					 | 
				
			||||||
			wdata->leds[i] = NULL;
 | 
					 | 
				
			||||||
			kfree(led);
 | 
					 | 
				
			||||||
			hid_warn(hdev, "can't register LED\n");
 | 
					 | 
				
			||||||
			goto err;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
err:
 | 
					 | 
				
			||||||
	return ret;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void wacom_destroy_leds(struct hid_device *hdev)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct wacom_data *wdata = hid_get_drvdata(hdev);
 | 
					 | 
				
			||||||
	struct led_classdev *led;
 | 
					 | 
				
			||||||
	int i;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for (i = 0; i < 4; ++i) {
 | 
					 | 
				
			||||||
		if (wdata->leds[i]) {
 | 
					 | 
				
			||||||
			led = wdata->leds[i];
 | 
					 | 
				
			||||||
			wdata->leds[i] = NULL;
 | 
					 | 
				
			||||||
			led_classdev_unregister(led);
 | 
					 | 
				
			||||||
			kfree(led);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int wacom_battery_get_property(struct power_supply *psy,
 | 
					 | 
				
			||||||
				enum power_supply_property psp,
 | 
					 | 
				
			||||||
				union power_supply_propval *val)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct wacom_data *wdata = container_of(psy,
 | 
					 | 
				
			||||||
					struct wacom_data, battery);
 | 
					 | 
				
			||||||
	int ret = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	switch (psp) {
 | 
					 | 
				
			||||||
	case POWER_SUPPLY_PROP_PRESENT:
 | 
					 | 
				
			||||||
		val->intval = 1;
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
	case POWER_SUPPLY_PROP_SCOPE:
 | 
					 | 
				
			||||||
		val->intval = POWER_SUPPLY_SCOPE_DEVICE;
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
	case POWER_SUPPLY_PROP_CAPACITY:
 | 
					 | 
				
			||||||
		val->intval = wdata->battery_capacity;
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
	case POWER_SUPPLY_PROP_STATUS:
 | 
					 | 
				
			||||||
		if (wdata->bat_charging)
 | 
					 | 
				
			||||||
			val->intval = POWER_SUPPLY_STATUS_CHARGING;
 | 
					 | 
				
			||||||
		else
 | 
					 | 
				
			||||||
			if (wdata->battery_capacity == 100 && wdata->ps_connected)
 | 
					 | 
				
			||||||
				val->intval = POWER_SUPPLY_STATUS_FULL;
 | 
					 | 
				
			||||||
			else
 | 
					 | 
				
			||||||
				val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
	default:
 | 
					 | 
				
			||||||
		ret = -EINVAL;
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return ret;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int wacom_ac_get_property(struct power_supply *psy,
 | 
					 | 
				
			||||||
				enum power_supply_property psp,
 | 
					 | 
				
			||||||
				union power_supply_propval *val)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct wacom_data *wdata = container_of(psy, struct wacom_data, ac);
 | 
					 | 
				
			||||||
	int ret = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	switch (psp) {
 | 
					 | 
				
			||||||
	case POWER_SUPPLY_PROP_PRESENT:
 | 
					 | 
				
			||||||
		/* fall through */
 | 
					 | 
				
			||||||
	case POWER_SUPPLY_PROP_ONLINE:
 | 
					 | 
				
			||||||
		val->intval = wdata->ps_connected;
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
	case POWER_SUPPLY_PROP_SCOPE:
 | 
					 | 
				
			||||||
		val->intval = POWER_SUPPLY_SCOPE_DEVICE;
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
	default:
 | 
					 | 
				
			||||||
		ret = -EINVAL;
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return ret;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void wacom_set_features(struct hid_device *hdev, u8 speed)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct wacom_data *wdata = hid_get_drvdata(hdev);
 | 
					 | 
				
			||||||
	int limit, ret;
 | 
					 | 
				
			||||||
	__u8 rep_data[2];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	switch (hdev->product) {
 | 
					 | 
				
			||||||
	case USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH:
 | 
					 | 
				
			||||||
		rep_data[0] = 0x03 ; rep_data[1] = 0x00;
 | 
					 | 
				
			||||||
		limit = 3;
 | 
					 | 
				
			||||||
		do {
 | 
					 | 
				
			||||||
			ret = hid_hw_raw_request(hdev, rep_data[0], rep_data, 2,
 | 
					 | 
				
			||||||
					HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
 | 
					 | 
				
			||||||
		} while (ret < 0 && limit-- > 0);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (ret >= 0) {
 | 
					 | 
				
			||||||
			if (speed == 0)
 | 
					 | 
				
			||||||
				rep_data[0] = 0x05;
 | 
					 | 
				
			||||||
			else
 | 
					 | 
				
			||||||
				rep_data[0] = 0x06;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			rep_data[1] = 0x00;
 | 
					 | 
				
			||||||
			limit = 3;
 | 
					 | 
				
			||||||
			do {
 | 
					 | 
				
			||||||
				ret = hid_hw_raw_request(hdev, rep_data[0],
 | 
					 | 
				
			||||||
					rep_data, 2, HID_FEATURE_REPORT,
 | 
					 | 
				
			||||||
					HID_REQ_SET_REPORT);
 | 
					 | 
				
			||||||
			} while (ret < 0 && limit-- > 0);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			if (ret >= 0) {
 | 
					 | 
				
			||||||
				wdata->high_speed = speed;
 | 
					 | 
				
			||||||
				return;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		/*
 | 
					 | 
				
			||||||
		 * Note that if the raw queries fail, it's not a hard failure
 | 
					 | 
				
			||||||
		 * and it is safe to continue
 | 
					 | 
				
			||||||
		 */
 | 
					 | 
				
			||||||
		hid_warn(hdev, "failed to poke device, command %d, err %d\n",
 | 
					 | 
				
			||||||
			 rep_data[0], ret);
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
	case USB_DEVICE_ID_WACOM_INTUOS4_BLUETOOTH:
 | 
					 | 
				
			||||||
		if (speed == 1)
 | 
					 | 
				
			||||||
			wdata->features &= ~0x20;
 | 
					 | 
				
			||||||
		else
 | 
					 | 
				
			||||||
			wdata->features |= 0x20;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		rep_data[0] = 0x03;
 | 
					 | 
				
			||||||
		rep_data[1] = wdata->features;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		ret = hid_hw_raw_request(hdev, rep_data[0], rep_data, 2,
 | 
					 | 
				
			||||||
				HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
 | 
					 | 
				
			||||||
		if (ret >= 0)
 | 
					 | 
				
			||||||
			wdata->high_speed = speed;
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static ssize_t wacom_show_speed(struct device *dev,
 | 
					 | 
				
			||||||
				struct device_attribute
 | 
					 | 
				
			||||||
				*attr, char *buf)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct wacom_data *wdata = dev_get_drvdata(dev);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return snprintf(buf, PAGE_SIZE, "%i\n", wdata->high_speed);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static ssize_t wacom_store_speed(struct device *dev,
 | 
					 | 
				
			||||||
				struct device_attribute *attr,
 | 
					 | 
				
			||||||
				const char *buf, size_t count)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct hid_device *hdev = container_of(dev, struct hid_device, dev);
 | 
					 | 
				
			||||||
	int new_speed;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (sscanf(buf, "%1d", &new_speed ) != 1)
 | 
					 | 
				
			||||||
		return -EINVAL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (new_speed == 0 || new_speed == 1) {
 | 
					 | 
				
			||||||
		wacom_set_features(hdev, new_speed);
 | 
					 | 
				
			||||||
		return strnlen(buf, PAGE_SIZE);
 | 
					 | 
				
			||||||
	} else
 | 
					 | 
				
			||||||
		return -EINVAL;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static DEVICE_ATTR(speed, S_IRUGO | S_IWUSR | S_IWGRP,
 | 
					 | 
				
			||||||
		wacom_show_speed, wacom_store_speed);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define WACOM_STORE(OLED_ID)						\
 | 
					 | 
				
			||||||
static ssize_t wacom_oled##OLED_ID##_store(struct device *dev,		\
 | 
					 | 
				
			||||||
				struct device_attribute *attr,		\
 | 
					 | 
				
			||||||
				const char *buf, size_t count)		\
 | 
					 | 
				
			||||||
{									\
 | 
					 | 
				
			||||||
	struct hid_device *hdev = container_of(dev, struct hid_device,	\
 | 
					 | 
				
			||||||
				dev);					\
 | 
					 | 
				
			||||||
									\
 | 
					 | 
				
			||||||
	if (count != 256)						\
 | 
					 | 
				
			||||||
		return -EINVAL;						\
 | 
					 | 
				
			||||||
									\
 | 
					 | 
				
			||||||
	wacom_set_image(hdev, buf, OLED_ID);				\
 | 
					 | 
				
			||||||
									\
 | 
					 | 
				
			||||||
	return count;							\
 | 
					 | 
				
			||||||
}									\
 | 
					 | 
				
			||||||
									\
 | 
					 | 
				
			||||||
static DEVICE_ATTR(oled##OLED_ID##_img, S_IWUSR | S_IWGRP, NULL,	\
 | 
					 | 
				
			||||||
				wacom_oled##OLED_ID##_store)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
WACOM_STORE(0);
 | 
					 | 
				
			||||||
WACOM_STORE(1);
 | 
					 | 
				
			||||||
WACOM_STORE(2);
 | 
					 | 
				
			||||||
WACOM_STORE(3);
 | 
					 | 
				
			||||||
WACOM_STORE(4);
 | 
					 | 
				
			||||||
WACOM_STORE(5);
 | 
					 | 
				
			||||||
WACOM_STORE(6);
 | 
					 | 
				
			||||||
WACOM_STORE(7);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int wacom_gr_parse_report(struct hid_device *hdev,
 | 
					 | 
				
			||||||
			struct wacom_data *wdata,
 | 
					 | 
				
			||||||
			struct input_dev *input, unsigned char *data)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	int tool, x, y, rw;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	tool = 0;
 | 
					 | 
				
			||||||
	/* Get X & Y positions */
 | 
					 | 
				
			||||||
	x = le16_to_cpu(*(__le16 *) &data[2]);
 | 
					 | 
				
			||||||
	y = le16_to_cpu(*(__le16 *) &data[4]);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Get current tool identifier */
 | 
					 | 
				
			||||||
	if (data[1] & 0x90) { /* If pen is in the in/active area */
 | 
					 | 
				
			||||||
		switch ((data[1] >> 5) & 3) {
 | 
					 | 
				
			||||||
		case 0:	/* Pen */
 | 
					 | 
				
			||||||
			tool = BTN_TOOL_PEN;
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		case 1: /* Rubber */
 | 
					 | 
				
			||||||
			tool = BTN_TOOL_RUBBER;
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		case 2: /* Mouse with wheel */
 | 
					 | 
				
			||||||
		case 3: /* Mouse without wheel */
 | 
					 | 
				
			||||||
			tool = BTN_TOOL_MOUSE;
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		/* Reset tool if out of active tablet area */
 | 
					 | 
				
			||||||
		if (!(data[1] & 0x10))
 | 
					 | 
				
			||||||
			tool = 0;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* If tool changed, notify input subsystem */
 | 
					 | 
				
			||||||
	if (wdata->tool != tool) {
 | 
					 | 
				
			||||||
		if (wdata->tool) {
 | 
					 | 
				
			||||||
			/* Completely reset old tool state */
 | 
					 | 
				
			||||||
			if (wdata->tool == BTN_TOOL_MOUSE) {
 | 
					 | 
				
			||||||
				input_report_key(input, BTN_LEFT, 0);
 | 
					 | 
				
			||||||
				input_report_key(input, BTN_RIGHT, 0);
 | 
					 | 
				
			||||||
				input_report_key(input, BTN_MIDDLE, 0);
 | 
					 | 
				
			||||||
				input_report_abs(input, ABS_DISTANCE,
 | 
					 | 
				
			||||||
					input_abs_get_max(input, ABS_DISTANCE));
 | 
					 | 
				
			||||||
			} else {
 | 
					 | 
				
			||||||
				input_report_key(input, BTN_TOUCH, 0);
 | 
					 | 
				
			||||||
				input_report_key(input, BTN_STYLUS, 0);
 | 
					 | 
				
			||||||
				input_report_key(input, BTN_STYLUS2, 0);
 | 
					 | 
				
			||||||
				input_report_abs(input, ABS_PRESSURE, 0);
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			input_report_key(input, wdata->tool, 0);
 | 
					 | 
				
			||||||
			input_sync(input);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		wdata->tool = tool;
 | 
					 | 
				
			||||||
		if (tool)
 | 
					 | 
				
			||||||
			input_report_key(input, tool, 1);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (tool) {
 | 
					 | 
				
			||||||
		input_report_abs(input, ABS_X, x);
 | 
					 | 
				
			||||||
		input_report_abs(input, ABS_Y, y);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		switch ((data[1] >> 5) & 3) {
 | 
					 | 
				
			||||||
		case 2: /* Mouse with wheel */
 | 
					 | 
				
			||||||
			input_report_key(input, BTN_MIDDLE, data[1] & 0x04);
 | 
					 | 
				
			||||||
			rw = (data[6] & 0x01) ? -1 :
 | 
					 | 
				
			||||||
				(data[6] & 0x02) ? 1 : 0;
 | 
					 | 
				
			||||||
			input_report_rel(input, REL_WHEEL, rw);
 | 
					 | 
				
			||||||
			/* fall through */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		case 3: /* Mouse without wheel */
 | 
					 | 
				
			||||||
			input_report_key(input, BTN_LEFT, data[1] & 0x01);
 | 
					 | 
				
			||||||
			input_report_key(input, BTN_RIGHT, data[1] & 0x02);
 | 
					 | 
				
			||||||
			/* Compute distance between mouse and tablet */
 | 
					 | 
				
			||||||
			rw = 44 - (data[6] >> 2);
 | 
					 | 
				
			||||||
			if (rw < 0)
 | 
					 | 
				
			||||||
				rw = 0;
 | 
					 | 
				
			||||||
			else if (rw > 31)
 | 
					 | 
				
			||||||
				rw = 31;
 | 
					 | 
				
			||||||
			input_report_abs(input, ABS_DISTANCE, rw);
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		default:
 | 
					 | 
				
			||||||
			input_report_abs(input, ABS_PRESSURE,
 | 
					 | 
				
			||||||
					data[6] | (((__u16) (data[1] & 0x08)) << 5));
 | 
					 | 
				
			||||||
			input_report_key(input, BTN_TOUCH, data[1] & 0x01);
 | 
					 | 
				
			||||||
			input_report_key(input, BTN_STYLUS, data[1] & 0x02);
 | 
					 | 
				
			||||||
			input_report_key(input, BTN_STYLUS2, (tool == BTN_TOOL_PEN) && data[1] & 0x04);
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		input_sync(input);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Report the state of the two buttons at the top of the tablet
 | 
					 | 
				
			||||||
	 * as two extra fingerpad keys (buttons 4 & 5). */
 | 
					 | 
				
			||||||
	rw = data[7] & 0x03;
 | 
					 | 
				
			||||||
	if (rw != wdata->butstate) {
 | 
					 | 
				
			||||||
		wdata->butstate = rw;
 | 
					 | 
				
			||||||
		input_report_key(input, BTN_0, rw & 0x02);
 | 
					 | 
				
			||||||
		input_report_key(input, BTN_1, rw & 0x01);
 | 
					 | 
				
			||||||
		input_report_key(input, BTN_TOOL_FINGER, 0xf0);
 | 
					 | 
				
			||||||
		input_event(input, EV_MSC, MSC_SERIAL, 0xf0);
 | 
					 | 
				
			||||||
		input_sync(input);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Store current battery capacity and power supply state*/
 | 
					 | 
				
			||||||
	rw = (data[7] >> 2 & 0x07);
 | 
					 | 
				
			||||||
	if (rw != wdata->power_raw) {
 | 
					 | 
				
			||||||
		wdata->power_raw = rw;
 | 
					 | 
				
			||||||
		wdata->battery_capacity = batcap_gr[rw];
 | 
					 | 
				
			||||||
		if (rw == 7)
 | 
					 | 
				
			||||||
			wdata->ps_connected = 1;
 | 
					 | 
				
			||||||
		else
 | 
					 | 
				
			||||||
			wdata->ps_connected = 0;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return 1;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void wacom_i4_parse_button_report(struct wacom_data *wdata,
 | 
					 | 
				
			||||||
			struct input_dev *input, unsigned char *data)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	__u16 new_butstate;
 | 
					 | 
				
			||||||
	__u8 new_whlstate;
 | 
					 | 
				
			||||||
	__u8 sync = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	new_whlstate = data[1];
 | 
					 | 
				
			||||||
	if (new_whlstate != wdata->whlstate) {
 | 
					 | 
				
			||||||
		wdata->whlstate = new_whlstate;
 | 
					 | 
				
			||||||
		if (new_whlstate & 0x80) {
 | 
					 | 
				
			||||||
			input_report_key(input, BTN_TOUCH, 1);
 | 
					 | 
				
			||||||
			input_report_abs(input, ABS_WHEEL, (new_whlstate & 0x7f));
 | 
					 | 
				
			||||||
			input_report_key(input, BTN_TOOL_FINGER, 1);
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			input_report_key(input, BTN_TOUCH, 0);
 | 
					 | 
				
			||||||
			input_report_abs(input, ABS_WHEEL, 0);
 | 
					 | 
				
			||||||
			input_report_key(input, BTN_TOOL_FINGER, 0);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		sync = 1;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	new_butstate = (data[3] << 1) | (data[2] & 0x01);
 | 
					 | 
				
			||||||
	if (new_butstate != wdata->butstate) {
 | 
					 | 
				
			||||||
		wdata->butstate = new_butstate;
 | 
					 | 
				
			||||||
		input_report_key(input, BTN_0, new_butstate & 0x001);
 | 
					 | 
				
			||||||
		input_report_key(input, BTN_1, new_butstate & 0x002);
 | 
					 | 
				
			||||||
		input_report_key(input, BTN_2, new_butstate & 0x004);
 | 
					 | 
				
			||||||
		input_report_key(input, BTN_3, new_butstate & 0x008);
 | 
					 | 
				
			||||||
		input_report_key(input, BTN_4, new_butstate & 0x010);
 | 
					 | 
				
			||||||
		input_report_key(input, BTN_5, new_butstate & 0x020);
 | 
					 | 
				
			||||||
		input_report_key(input, BTN_6, new_butstate & 0x040);
 | 
					 | 
				
			||||||
		input_report_key(input, BTN_7, new_butstate & 0x080);
 | 
					 | 
				
			||||||
		input_report_key(input, BTN_8, new_butstate & 0x100);
 | 
					 | 
				
			||||||
		input_report_key(input, BTN_TOOL_FINGER, 1);
 | 
					 | 
				
			||||||
		sync = 1;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (sync) {
 | 
					 | 
				
			||||||
		input_report_abs(input, ABS_MISC, PAD_DEVICE_ID);
 | 
					 | 
				
			||||||
		input_event(input, EV_MSC, MSC_SERIAL, 0xffffffff);
 | 
					 | 
				
			||||||
		input_sync(input);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void wacom_i4_parse_pen_report(struct wacom_data *wdata,
 | 
					 | 
				
			||||||
			struct input_dev *input, unsigned char *data)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	__u16 x, y, pressure;
 | 
					 | 
				
			||||||
	__u8 distance;
 | 
					 | 
				
			||||||
	__u8 tilt_x, tilt_y;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	switch (data[1]) {
 | 
					 | 
				
			||||||
	case 0x80: /* Out of proximity report */
 | 
					 | 
				
			||||||
		input_report_key(input, BTN_TOUCH, 0);
 | 
					 | 
				
			||||||
		input_report_abs(input, ABS_PRESSURE, 0);
 | 
					 | 
				
			||||||
		input_report_key(input, BTN_STYLUS, 0);
 | 
					 | 
				
			||||||
		input_report_key(input, BTN_STYLUS2, 0);
 | 
					 | 
				
			||||||
		input_report_key(input, wdata->tool, 0);
 | 
					 | 
				
			||||||
		input_report_abs(input, ABS_MISC, 0);
 | 
					 | 
				
			||||||
		input_event(input, EV_MSC, MSC_SERIAL, wdata->serial);
 | 
					 | 
				
			||||||
		wdata->tool = 0;
 | 
					 | 
				
			||||||
		input_sync(input);
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
	case 0xC2: /* Tool report */
 | 
					 | 
				
			||||||
		wdata->id = ((data[2] << 4) | (data[3] >> 4) |
 | 
					 | 
				
			||||||
			((data[7] & 0x0f) << 20) |
 | 
					 | 
				
			||||||
			((data[8] & 0xf0) << 12));
 | 
					 | 
				
			||||||
		wdata->serial = ((data[3] & 0x0f) << 28) +
 | 
					 | 
				
			||||||
				(data[4] << 20) + (data[5] << 12) +
 | 
					 | 
				
			||||||
				(data[6] << 4) + (data[7] >> 4);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		switch (wdata->id) {
 | 
					 | 
				
			||||||
		case 0x100802:
 | 
					 | 
				
			||||||
			wdata->tool = BTN_TOOL_PEN;
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		case 0x10080A:
 | 
					 | 
				
			||||||
			wdata->tool = BTN_TOOL_RUBBER;
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
	default: /* Position/pressure report */
 | 
					 | 
				
			||||||
		x = data[2] << 9 | data[3] << 1 | ((data[9] & 0x02) >> 1);
 | 
					 | 
				
			||||||
		y = data[4] << 9 | data[5] << 1 | (data[9] & 0x01);
 | 
					 | 
				
			||||||
		pressure = (data[6] << 3) | ((data[7] & 0xC0) >> 5)
 | 
					 | 
				
			||||||
			| (data[1] & 0x01);
 | 
					 | 
				
			||||||
		distance = (data[9] >> 2) & 0x3f;
 | 
					 | 
				
			||||||
		tilt_x = ((data[7] << 1) & 0x7e) | (data[8] >> 7);
 | 
					 | 
				
			||||||
		tilt_y = data[8] & 0x7f;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		input_report_key(input, BTN_TOUCH, pressure > 1);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		input_report_key(input, BTN_STYLUS, data[1] & 0x02);
 | 
					 | 
				
			||||||
		input_report_key(input, BTN_STYLUS2, data[1] & 0x04);
 | 
					 | 
				
			||||||
		input_report_key(input, wdata->tool, 1);
 | 
					 | 
				
			||||||
		input_report_abs(input, ABS_X, x);
 | 
					 | 
				
			||||||
		input_report_abs(input, ABS_Y, y);
 | 
					 | 
				
			||||||
		input_report_abs(input, ABS_PRESSURE, pressure);
 | 
					 | 
				
			||||||
		input_report_abs(input, ABS_DISTANCE, distance);
 | 
					 | 
				
			||||||
		input_report_abs(input, ABS_TILT_X, tilt_x);
 | 
					 | 
				
			||||||
		input_report_abs(input, ABS_TILT_Y, tilt_y);
 | 
					 | 
				
			||||||
		input_report_abs(input, ABS_MISC, wdata->id);
 | 
					 | 
				
			||||||
		input_event(input, EV_MSC, MSC_SERIAL, wdata->serial);
 | 
					 | 
				
			||||||
		input_report_key(input, wdata->tool, 1);
 | 
					 | 
				
			||||||
		input_sync(input);
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void wacom_i4_parse_report(struct hid_device *hdev,
 | 
					 | 
				
			||||||
			struct wacom_data *wdata,
 | 
					 | 
				
			||||||
			struct input_dev *input, unsigned char *data)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	switch (data[0]) {
 | 
					 | 
				
			||||||
	case 0x00: /* Empty report */
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
	case 0x02: /* Pen report */
 | 
					 | 
				
			||||||
		wacom_i4_parse_pen_report(wdata, input, data);
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
	case 0x03: /* Features Report */
 | 
					 | 
				
			||||||
		wdata->features = data[2];
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
	case 0x0C: /* Button report */
 | 
					 | 
				
			||||||
		wacom_i4_parse_button_report(wdata, input, data);
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
	default:
 | 
					 | 
				
			||||||
		hid_err(hdev, "Unknown report: %d,%d\n", data[0], data[1]);
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int wacom_raw_event(struct hid_device *hdev, struct hid_report *report,
 | 
					 | 
				
			||||||
		u8 *raw_data, int size)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct wacom_data *wdata = hid_get_drvdata(hdev);
 | 
					 | 
				
			||||||
	struct hid_input *hidinput;
 | 
					 | 
				
			||||||
	struct input_dev *input;
 | 
					 | 
				
			||||||
	unsigned char *data = (unsigned char *) raw_data;
 | 
					 | 
				
			||||||
	int i;
 | 
					 | 
				
			||||||
	__u8 power_raw;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!(hdev->claimed & HID_CLAIMED_INPUT))
 | 
					 | 
				
			||||||
		return 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	hidinput = list_entry(hdev->inputs.next, struct hid_input, list);
 | 
					 | 
				
			||||||
	input = hidinput->input;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	switch (hdev->product) {
 | 
					 | 
				
			||||||
	case USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH:
 | 
					 | 
				
			||||||
		if (data[0] == 0x03) {
 | 
					 | 
				
			||||||
			return wacom_gr_parse_report(hdev, wdata, input, data);
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			hid_err(hdev, "Unknown report: %d,%d size:%d\n",
 | 
					 | 
				
			||||||
					data[0], data[1], size);
 | 
					 | 
				
			||||||
			return 0;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
	case USB_DEVICE_ID_WACOM_INTUOS4_BLUETOOTH:
 | 
					 | 
				
			||||||
		i = 1;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		switch (data[0]) {
 | 
					 | 
				
			||||||
		case 0x04:
 | 
					 | 
				
			||||||
			wacom_i4_parse_report(hdev, wdata, input, data + i);
 | 
					 | 
				
			||||||
			i += 10;
 | 
					 | 
				
			||||||
			/* fall through */
 | 
					 | 
				
			||||||
		case 0x03:
 | 
					 | 
				
			||||||
			wacom_i4_parse_report(hdev, wdata, input, data + i);
 | 
					 | 
				
			||||||
			i += 10;
 | 
					 | 
				
			||||||
			wacom_i4_parse_report(hdev, wdata, input, data + i);
 | 
					 | 
				
			||||||
			power_raw = data[i+10];
 | 
					 | 
				
			||||||
			if (power_raw != wdata->power_raw) {
 | 
					 | 
				
			||||||
				wdata->power_raw = power_raw;
 | 
					 | 
				
			||||||
				wdata->battery_capacity = batcap_i4[power_raw & 0x07];
 | 
					 | 
				
			||||||
				wdata->bat_charging = (power_raw & 0x08) ? 1 : 0;
 | 
					 | 
				
			||||||
				wdata->ps_connected = (power_raw & 0x10) ? 1 : 0;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		default:
 | 
					 | 
				
			||||||
			hid_err(hdev, "Unknown report: %d,%d size:%d\n",
 | 
					 | 
				
			||||||
					data[0], data[1], size);
 | 
					 | 
				
			||||||
			return 0;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return 1;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int wacom_input_mapped(struct hid_device *hdev, struct hid_input *hi,
 | 
					 | 
				
			||||||
	struct hid_field *field, struct hid_usage *usage, unsigned long **bit,
 | 
					 | 
				
			||||||
								int *max)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct input_dev *input = hi->input;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	__set_bit(INPUT_PROP_POINTER, input->propbit);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Basics */
 | 
					 | 
				
			||||||
	input->evbit[0] |= BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_REL);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	__set_bit(REL_WHEEL, input->relbit);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	__set_bit(BTN_TOOL_PEN, input->keybit);
 | 
					 | 
				
			||||||
	__set_bit(BTN_TOUCH, input->keybit);
 | 
					 | 
				
			||||||
	__set_bit(BTN_STYLUS, input->keybit);
 | 
					 | 
				
			||||||
	__set_bit(BTN_STYLUS2, input->keybit);
 | 
					 | 
				
			||||||
	__set_bit(BTN_LEFT, input->keybit);
 | 
					 | 
				
			||||||
	__set_bit(BTN_RIGHT, input->keybit);
 | 
					 | 
				
			||||||
	__set_bit(BTN_MIDDLE, input->keybit);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Pad */
 | 
					 | 
				
			||||||
	input_set_capability(input, EV_MSC, MSC_SERIAL);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	__set_bit(BTN_0, input->keybit);
 | 
					 | 
				
			||||||
	__set_bit(BTN_1, input->keybit);
 | 
					 | 
				
			||||||
	__set_bit(BTN_TOOL_FINGER, input->keybit);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Distance, rubber and mouse */
 | 
					 | 
				
			||||||
	__set_bit(BTN_TOOL_RUBBER, input->keybit);
 | 
					 | 
				
			||||||
	__set_bit(BTN_TOOL_MOUSE, input->keybit);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	switch (hdev->product) {
 | 
					 | 
				
			||||||
	case USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH:
 | 
					 | 
				
			||||||
		input_set_abs_params(input, ABS_X, 0, 16704, 4, 0);
 | 
					 | 
				
			||||||
		input_set_abs_params(input, ABS_Y, 0, 12064, 4, 0);
 | 
					 | 
				
			||||||
		input_set_abs_params(input, ABS_PRESSURE, 0, 511, 0, 0);
 | 
					 | 
				
			||||||
		input_set_abs_params(input, ABS_DISTANCE, 0, 32, 0, 0);
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
	case USB_DEVICE_ID_WACOM_INTUOS4_BLUETOOTH:
 | 
					 | 
				
			||||||
		__set_bit(ABS_WHEEL, input->absbit);
 | 
					 | 
				
			||||||
		__set_bit(ABS_MISC, input->absbit);
 | 
					 | 
				
			||||||
		__set_bit(BTN_2, input->keybit);
 | 
					 | 
				
			||||||
		__set_bit(BTN_3, input->keybit);
 | 
					 | 
				
			||||||
		__set_bit(BTN_4, input->keybit);
 | 
					 | 
				
			||||||
		__set_bit(BTN_5, input->keybit);
 | 
					 | 
				
			||||||
		__set_bit(BTN_6, input->keybit);
 | 
					 | 
				
			||||||
		__set_bit(BTN_7, input->keybit);
 | 
					 | 
				
			||||||
		__set_bit(BTN_8, input->keybit);
 | 
					 | 
				
			||||||
		input_set_abs_params(input, ABS_WHEEL, 0, 71, 0, 0);
 | 
					 | 
				
			||||||
		input_set_abs_params(input, ABS_X, 0, 40640, 4, 0);
 | 
					 | 
				
			||||||
		input_set_abs_params(input, ABS_Y, 0, 25400, 4, 0);
 | 
					 | 
				
			||||||
		input_set_abs_params(input, ABS_PRESSURE, 0, 2047, 0, 0);
 | 
					 | 
				
			||||||
		input_set_abs_params(input, ABS_DISTANCE, 0, 63, 0, 0);
 | 
					 | 
				
			||||||
		input_set_abs_params(input, ABS_TILT_X, 0, 127, 0, 0);
 | 
					 | 
				
			||||||
		input_set_abs_params(input, ABS_TILT_Y, 0, 127, 0, 0);
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int wacom_probe(struct hid_device *hdev,
 | 
					 | 
				
			||||||
		const struct hid_device_id *id)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct wacom_data *wdata;
 | 
					 | 
				
			||||||
	int ret;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	wdata = kzalloc(sizeof(*wdata), GFP_KERNEL);
 | 
					 | 
				
			||||||
	if (wdata == NULL) {
 | 
					 | 
				
			||||||
		hid_err(hdev, "can't alloc wacom descriptor\n");
 | 
					 | 
				
			||||||
		return -ENOMEM;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	hid_set_drvdata(hdev, wdata);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Parse the HID report now */
 | 
					 | 
				
			||||||
	ret = hid_parse(hdev);
 | 
					 | 
				
			||||||
	if (ret) {
 | 
					 | 
				
			||||||
		hid_err(hdev, "parse failed\n");
 | 
					 | 
				
			||||||
		goto err_free;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
 | 
					 | 
				
			||||||
	if (ret) {
 | 
					 | 
				
			||||||
		hid_err(hdev, "hw start failed\n");
 | 
					 | 
				
			||||||
		goto err_free;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ret = device_create_file(&hdev->dev, &dev_attr_speed);
 | 
					 | 
				
			||||||
	if (ret)
 | 
					 | 
				
			||||||
		hid_warn(hdev,
 | 
					 | 
				
			||||||
			 "can't create sysfs speed attribute err: %d\n", ret);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define OLED_INIT(OLED_ID)						\
 | 
					 | 
				
			||||||
	do {								\
 | 
					 | 
				
			||||||
		ret = device_create_file(&hdev->dev,			\
 | 
					 | 
				
			||||||
				&dev_attr_oled##OLED_ID##_img);		\
 | 
					 | 
				
			||||||
		if (ret)						\
 | 
					 | 
				
			||||||
			hid_warn(hdev,					\
 | 
					 | 
				
			||||||
			 "can't create sysfs oled attribute, err: %d\n", ret);\
 | 
					 | 
				
			||||||
	} while (0)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
OLED_INIT(0);
 | 
					 | 
				
			||||||
OLED_INIT(1);
 | 
					 | 
				
			||||||
OLED_INIT(2);
 | 
					 | 
				
			||||||
OLED_INIT(3);
 | 
					 | 
				
			||||||
OLED_INIT(4);
 | 
					 | 
				
			||||||
OLED_INIT(5);
 | 
					 | 
				
			||||||
OLED_INIT(6);
 | 
					 | 
				
			||||||
OLED_INIT(7);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	wdata->features = 0;
 | 
					 | 
				
			||||||
	wacom_set_features(hdev, 1);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (hdev->product == USB_DEVICE_ID_WACOM_INTUOS4_BLUETOOTH) {
 | 
					 | 
				
			||||||
		sprintf(hdev->name, "%s", "Wacom Intuos4 WL");
 | 
					 | 
				
			||||||
		ret = wacom_initialize_leds(hdev);
 | 
					 | 
				
			||||||
		if (ret)
 | 
					 | 
				
			||||||
			hid_warn(hdev,
 | 
					 | 
				
			||||||
				 "can't create led attribute, err: %d\n", ret);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	wdata->battery.properties = wacom_battery_props;
 | 
					 | 
				
			||||||
	wdata->battery.num_properties = ARRAY_SIZE(wacom_battery_props);
 | 
					 | 
				
			||||||
	wdata->battery.get_property = wacom_battery_get_property;
 | 
					 | 
				
			||||||
	wdata->battery.name = "wacom_battery";
 | 
					 | 
				
			||||||
	wdata->battery.type = POWER_SUPPLY_TYPE_BATTERY;
 | 
					 | 
				
			||||||
	wdata->battery.use_for_apm = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ret = power_supply_register(&hdev->dev, &wdata->battery);
 | 
					 | 
				
			||||||
	if (ret) {
 | 
					 | 
				
			||||||
		hid_err(hdev, "can't create sysfs battery attribute, err: %d\n",
 | 
					 | 
				
			||||||
			ret);
 | 
					 | 
				
			||||||
		goto err_battery;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	power_supply_powers(&wdata->battery, &hdev->dev);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	wdata->ac.properties = wacom_ac_props;
 | 
					 | 
				
			||||||
	wdata->ac.num_properties = ARRAY_SIZE(wacom_ac_props);
 | 
					 | 
				
			||||||
	wdata->ac.get_property = wacom_ac_get_property;
 | 
					 | 
				
			||||||
	wdata->ac.name = "wacom_ac";
 | 
					 | 
				
			||||||
	wdata->ac.type = POWER_SUPPLY_TYPE_MAINS;
 | 
					 | 
				
			||||||
	wdata->ac.use_for_apm = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ret = power_supply_register(&hdev->dev, &wdata->ac);
 | 
					 | 
				
			||||||
	if (ret) {
 | 
					 | 
				
			||||||
		hid_err(hdev,
 | 
					 | 
				
			||||||
			"can't create ac battery attribute, err: %d\n", ret);
 | 
					 | 
				
			||||||
		goto err_ac;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	power_supply_powers(&wdata->ac, &hdev->dev);
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
err_ac:
 | 
					 | 
				
			||||||
	power_supply_unregister(&wdata->battery);
 | 
					 | 
				
			||||||
err_battery:
 | 
					 | 
				
			||||||
	wacom_destroy_leds(hdev);
 | 
					 | 
				
			||||||
	device_remove_file(&hdev->dev, &dev_attr_oled0_img);
 | 
					 | 
				
			||||||
	device_remove_file(&hdev->dev, &dev_attr_oled1_img);
 | 
					 | 
				
			||||||
	device_remove_file(&hdev->dev, &dev_attr_oled2_img);
 | 
					 | 
				
			||||||
	device_remove_file(&hdev->dev, &dev_attr_oled3_img);
 | 
					 | 
				
			||||||
	device_remove_file(&hdev->dev, &dev_attr_oled4_img);
 | 
					 | 
				
			||||||
	device_remove_file(&hdev->dev, &dev_attr_oled5_img);
 | 
					 | 
				
			||||||
	device_remove_file(&hdev->dev, &dev_attr_oled6_img);
 | 
					 | 
				
			||||||
	device_remove_file(&hdev->dev, &dev_attr_oled7_img);
 | 
					 | 
				
			||||||
	device_remove_file(&hdev->dev, &dev_attr_speed);
 | 
					 | 
				
			||||||
	hid_hw_stop(hdev);
 | 
					 | 
				
			||||||
err_free:
 | 
					 | 
				
			||||||
	kfree(wdata);
 | 
					 | 
				
			||||||
	return ret;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void wacom_remove(struct hid_device *hdev)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct wacom_data *wdata = hid_get_drvdata(hdev);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	wacom_destroy_leds(hdev);
 | 
					 | 
				
			||||||
	device_remove_file(&hdev->dev, &dev_attr_oled0_img);
 | 
					 | 
				
			||||||
	device_remove_file(&hdev->dev, &dev_attr_oled1_img);
 | 
					 | 
				
			||||||
	device_remove_file(&hdev->dev, &dev_attr_oled2_img);
 | 
					 | 
				
			||||||
	device_remove_file(&hdev->dev, &dev_attr_oled3_img);
 | 
					 | 
				
			||||||
	device_remove_file(&hdev->dev, &dev_attr_oled4_img);
 | 
					 | 
				
			||||||
	device_remove_file(&hdev->dev, &dev_attr_oled5_img);
 | 
					 | 
				
			||||||
	device_remove_file(&hdev->dev, &dev_attr_oled6_img);
 | 
					 | 
				
			||||||
	device_remove_file(&hdev->dev, &dev_attr_oled7_img);
 | 
					 | 
				
			||||||
	device_remove_file(&hdev->dev, &dev_attr_speed);
 | 
					 | 
				
			||||||
	hid_hw_stop(hdev);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	power_supply_unregister(&wdata->battery);
 | 
					 | 
				
			||||||
	power_supply_unregister(&wdata->ac);
 | 
					 | 
				
			||||||
	kfree(hid_get_drvdata(hdev));
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static const struct hid_device_id wacom_devices[] = {
 | 
					 | 
				
			||||||
	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH) },
 | 
					 | 
				
			||||||
	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS4_BLUETOOTH) },
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	{ }
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
MODULE_DEVICE_TABLE(hid, wacom_devices);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static struct hid_driver wacom_driver = {
 | 
					 | 
				
			||||||
	.name = "wacom",
 | 
					 | 
				
			||||||
	.id_table = wacom_devices,
 | 
					 | 
				
			||||||
	.probe = wacom_probe,
 | 
					 | 
				
			||||||
	.remove = wacom_remove,
 | 
					 | 
				
			||||||
	.raw_event = wacom_raw_event,
 | 
					 | 
				
			||||||
	.input_mapped = wacom_input_mapped,
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
module_hid_driver(wacom_driver);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
MODULE_DESCRIPTION("Driver for Wacom Graphire Bluetooth and Wacom Intuos4 WL");
 | 
					 | 
				
			||||||
MODULE_LICENSE("GPL");
 | 
					 | 
				
			||||||
| 
						 | 
					@ -12,6 +12,7 @@
 | 
				
			||||||
 *  Copyright (c) 2001 Frederic Lepied		<flepied@mandrakesoft.com>
 | 
					 *  Copyright (c) 2001 Frederic Lepied		<flepied@mandrakesoft.com>
 | 
				
			||||||
 *  Copyright (c) 2004 Panagiotis Issaris	<panagiotis.issaris@mech.kuleuven.ac.be>
 | 
					 *  Copyright (c) 2004 Panagiotis Issaris	<panagiotis.issaris@mech.kuleuven.ac.be>
 | 
				
			||||||
 *  Copyright (c) 2002-2011 Ping Cheng		<pingc@wacom.com>
 | 
					 *  Copyright (c) 2002-2011 Ping Cheng		<pingc@wacom.com>
 | 
				
			||||||
 | 
					 *  Copyright (c) 2014 Benjamin Tissoires	<benjamin.tissoires@redhat.com>
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 *  ChangeLog:
 | 
					 *  ChangeLog:
 | 
				
			||||||
 *      v0.1 (vp)  - Initial release
 | 
					 *      v0.1 (vp)  - Initial release
 | 
				
			||||||
| 
						 | 
					@ -72,6 +73,8 @@
 | 
				
			||||||
 *      v1.52 (pc) - Query Wacom data upon system resume
 | 
					 *      v1.52 (pc) - Query Wacom data upon system resume
 | 
				
			||||||
 *                 - add defines for features->type
 | 
					 *                 - add defines for features->type
 | 
				
			||||||
 *                 - add new devices (0x9F, 0xE2, and 0XE3)
 | 
					 *                 - add new devices (0x9F, 0xE2, and 0XE3)
 | 
				
			||||||
 | 
					 *      v2.00 (bt) - conversion to a HID driver
 | 
				
			||||||
 | 
					 *                 - integration of the Bluetooth devices
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
| 
						 | 
					@ -93,35 +96,30 @@
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Version Information
 | 
					 * Version Information
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
#define DRIVER_VERSION "v1.53"
 | 
					#define DRIVER_VERSION "v2.00"
 | 
				
			||||||
#define DRIVER_AUTHOR "Vojtech Pavlik <vojtech@ucw.cz>"
 | 
					#define DRIVER_AUTHOR "Vojtech Pavlik <vojtech@ucw.cz>"
 | 
				
			||||||
#define DRIVER_DESC "USB Wacom tablet driver"
 | 
					#define DRIVER_DESC "USB Wacom tablet driver"
 | 
				
			||||||
#define DRIVER_LICENSE "GPL"
 | 
					#define DRIVER_LICENSE "GPL"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
MODULE_AUTHOR(DRIVER_AUTHOR);
 | 
					 | 
				
			||||||
MODULE_DESCRIPTION(DRIVER_DESC);
 | 
					 | 
				
			||||||
MODULE_LICENSE(DRIVER_LICENSE);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define USB_VENDOR_ID_WACOM	0x056a
 | 
					#define USB_VENDOR_ID_WACOM	0x056a
 | 
				
			||||||
#define USB_VENDOR_ID_LENOVO	0x17ef
 | 
					#define USB_VENDOR_ID_LENOVO	0x17ef
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct wacom {
 | 
					struct wacom {
 | 
				
			||||||
	dma_addr_t data_dma;
 | 
					 | 
				
			||||||
	struct usb_device *usbdev;
 | 
						struct usb_device *usbdev;
 | 
				
			||||||
	struct usb_interface *intf;
 | 
						struct usb_interface *intf;
 | 
				
			||||||
	struct urb *irq;
 | 
					 | 
				
			||||||
	struct wacom_wac wacom_wac;
 | 
						struct wacom_wac wacom_wac;
 | 
				
			||||||
 | 
						struct hid_device *hdev;
 | 
				
			||||||
	struct mutex lock;
 | 
						struct mutex lock;
 | 
				
			||||||
	struct work_struct work;
 | 
						struct work_struct work;
 | 
				
			||||||
	bool open;
 | 
					 | 
				
			||||||
	char phys[32];
 | 
					 | 
				
			||||||
	struct wacom_led {
 | 
						struct wacom_led {
 | 
				
			||||||
		u8 select[2]; /* status led selector (0..3) */
 | 
							u8 select[2]; /* status led selector (0..3) */
 | 
				
			||||||
		u8 llv;       /* status led brightness no button (1..127) */
 | 
							u8 llv;       /* status led brightness no button (1..127) */
 | 
				
			||||||
		u8 hlv;       /* status led brightness button pressed (1..127) */
 | 
							u8 hlv;       /* status led brightness button pressed (1..127) */
 | 
				
			||||||
		u8 img_lum;   /* OLED matrix display brightness */
 | 
							u8 img_lum;   /* OLED matrix display brightness */
 | 
				
			||||||
	} led;
 | 
						} led;
 | 
				
			||||||
 | 
						bool led_initialized;
 | 
				
			||||||
	struct power_supply battery;
 | 
						struct power_supply battery;
 | 
				
			||||||
 | 
						struct power_supply ac;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline void wacom_schedule_work(struct wacom_wac *wacom_wac)
 | 
					static inline void wacom_schedule_work(struct wacom_wac *wacom_wac)
 | 
				
			||||||
| 
						 | 
					@ -130,10 +128,19 @@ static inline void wacom_schedule_work(struct wacom_wac *wacom_wac)
 | 
				
			||||||
	schedule_work(&wacom->work);
 | 
						schedule_work(&wacom->work);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern const struct usb_device_id wacom_ids[];
 | 
					static inline void wacom_notify_battery(struct wacom_wac *wacom_wac)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						power_supply_changed(&wacom->battery);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern const struct hid_device_id wacom_ids[];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len);
 | 
					void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len);
 | 
				
			||||||
void wacom_setup_device_quirks(struct wacom_features *features);
 | 
					void wacom_setup_device_quirks(struct wacom_features *features);
 | 
				
			||||||
int wacom_setup_input_capabilities(struct input_dev *input_dev,
 | 
					int wacom_setup_input_capabilities(struct input_dev *input_dev,
 | 
				
			||||||
				   struct wacom_wac *wacom_wac);
 | 
									   struct wacom_wac *wacom_wac);
 | 
				
			||||||
 | 
					int wacom_setup_pad_input_capabilities(struct input_dev *input_dev,
 | 
				
			||||||
 | 
									       struct wacom_wac *wacom_wac);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							| 
						 | 
					@ -46,6 +46,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* wacom data packet report IDs */
 | 
					/* wacom data packet report IDs */
 | 
				
			||||||
#define WACOM_REPORT_PENABLED		2
 | 
					#define WACOM_REPORT_PENABLED		2
 | 
				
			||||||
 | 
					#define WACOM_REPORT_PENABLED_BT	3
 | 
				
			||||||
#define WACOM_REPORT_INTUOSREAD		5
 | 
					#define WACOM_REPORT_INTUOSREAD		5
 | 
				
			||||||
#define WACOM_REPORT_INTUOSWRITE	6
 | 
					#define WACOM_REPORT_INTUOSWRITE	6
 | 
				
			||||||
#define WACOM_REPORT_INTUOSPAD		12
 | 
					#define WACOM_REPORT_INTUOSPAD		12
 | 
				
			||||||
| 
						 | 
					@ -68,10 +69,12 @@
 | 
				
			||||||
#define WACOM_QUIRK_BBTOUCH_LOWRES	0x0002
 | 
					#define WACOM_QUIRK_BBTOUCH_LOWRES	0x0002
 | 
				
			||||||
#define WACOM_QUIRK_NO_INPUT		0x0004
 | 
					#define WACOM_QUIRK_NO_INPUT		0x0004
 | 
				
			||||||
#define WACOM_QUIRK_MONITOR		0x0008
 | 
					#define WACOM_QUIRK_MONITOR		0x0008
 | 
				
			||||||
 | 
					#define WACOM_QUIRK_BATTERY		0x0010
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum {
 | 
					enum {
 | 
				
			||||||
	PENPARTNER = 0,
 | 
						PENPARTNER = 0,
 | 
				
			||||||
	GRAPHIRE,
 | 
						GRAPHIRE,
 | 
				
			||||||
 | 
						GRAPHIRE_BT,
 | 
				
			||||||
	WACOM_G4,
 | 
						WACOM_G4,
 | 
				
			||||||
	PTU,
 | 
						PTU,
 | 
				
			||||||
	PL,
 | 
						PL,
 | 
				
			||||||
| 
						 | 
					@ -83,6 +86,7 @@ enum {
 | 
				
			||||||
	INTUOS3L,
 | 
						INTUOS3L,
 | 
				
			||||||
	INTUOS4S,
 | 
						INTUOS4S,
 | 
				
			||||||
	INTUOS4,
 | 
						INTUOS4,
 | 
				
			||||||
 | 
						INTUOS4WL,
 | 
				
			||||||
	INTUOS4L,
 | 
						INTUOS4L,
 | 
				
			||||||
	INTUOS5S,
 | 
						INTUOS5S,
 | 
				
			||||||
	INTUOS5,
 | 
						INTUOS5,
 | 
				
			||||||
| 
						 | 
					@ -114,7 +118,6 @@ enum {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct wacom_features {
 | 
					struct wacom_features {
 | 
				
			||||||
	const char *name;
 | 
						const char *name;
 | 
				
			||||||
	int pktlen;
 | 
					 | 
				
			||||||
	int x_max;
 | 
						int x_max;
 | 
				
			||||||
	int y_max;
 | 
						int y_max;
 | 
				
			||||||
	int pressure_max;
 | 
						int pressure_max;
 | 
				
			||||||
| 
						 | 
					@ -127,8 +130,8 @@ struct wacom_features {
 | 
				
			||||||
	int device_type;
 | 
						int device_type;
 | 
				
			||||||
	int x_phy;
 | 
						int x_phy;
 | 
				
			||||||
	int y_phy;
 | 
						int y_phy;
 | 
				
			||||||
	unsigned char unit;
 | 
						unsigned unit;
 | 
				
			||||||
	unsigned char unitExpo;
 | 
						int unitExpo;
 | 
				
			||||||
	int x_fuzz;
 | 
						int x_fuzz;
 | 
				
			||||||
	int y_fuzz;
 | 
						int y_fuzz;
 | 
				
			||||||
	int pressure_fuzz;
 | 
						int pressure_fuzz;
 | 
				
			||||||
| 
						 | 
					@ -137,6 +140,9 @@ struct wacom_features {
 | 
				
			||||||
	unsigned touch_max;
 | 
						unsigned touch_max;
 | 
				
			||||||
	int oVid;
 | 
						int oVid;
 | 
				
			||||||
	int oPid;
 | 
						int oPid;
 | 
				
			||||||
 | 
						int pktlen;
 | 
				
			||||||
 | 
						bool check_for_hid_type;
 | 
				
			||||||
 | 
						int hid_type;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct wacom_shared {
 | 
					struct wacom_shared {
 | 
				
			||||||
| 
						 | 
					@ -150,16 +156,24 @@ struct wacom_shared {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct wacom_wac {
 | 
					struct wacom_wac {
 | 
				
			||||||
	char name[WACOM_NAME_MAX];
 | 
						char name[WACOM_NAME_MAX];
 | 
				
			||||||
	unsigned char *data;
 | 
						char pad_name[WACOM_NAME_MAX];
 | 
				
			||||||
 | 
						char bat_name[WACOM_NAME_MAX];
 | 
				
			||||||
 | 
						char ac_name[WACOM_NAME_MAX];
 | 
				
			||||||
 | 
						unsigned char data[WACOM_PKGLEN_MAX];
 | 
				
			||||||
	int tool[2];
 | 
						int tool[2];
 | 
				
			||||||
	int id[2];
 | 
						int id[2];
 | 
				
			||||||
	__u32 serial[2];
 | 
						__u32 serial[2];
 | 
				
			||||||
	struct wacom_features features;
 | 
						struct wacom_features features;
 | 
				
			||||||
	struct wacom_shared *shared;
 | 
						struct wacom_shared *shared;
 | 
				
			||||||
	struct input_dev *input;
 | 
						struct input_dev *input;
 | 
				
			||||||
 | 
						struct input_dev *pad_input;
 | 
				
			||||||
	int pid;
 | 
						int pid;
 | 
				
			||||||
	int battery_capacity;
 | 
						int battery_capacity;
 | 
				
			||||||
	int num_contacts_left;
 | 
						int num_contacts_left;
 | 
				
			||||||
 | 
						int bat_charging;
 | 
				
			||||||
 | 
						int ps_connected;
 | 
				
			||||||
 | 
						u8 bt_features;
 | 
				
			||||||
 | 
						u8 bt_high_speed;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					@ -665,4 +665,14 @@ config KEYBOARD_CROS_EC
 | 
				
			||||||
	  To compile this driver as a module, choose M here: the
 | 
						  To compile this driver as a module, choose M here: the
 | 
				
			||||||
	  module will be called cros_ec_keyb.
 | 
						  module will be called cros_ec_keyb.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					config KEYBOARD_CAP1106
 | 
				
			||||||
 | 
						tristate "Microchip CAP1106 touch sensor"
 | 
				
			||||||
 | 
						depends on OF && I2C
 | 
				
			||||||
 | 
						select REGMAP_I2C
 | 
				
			||||||
 | 
						help
 | 
				
			||||||
 | 
						  Say Y here to enable the CAP1106 touch sensor driver.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						  To compile this driver as a module, choose M here: the
 | 
				
			||||||
 | 
						  module will be called cap1106.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
endif
 | 
					endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -11,6 +11,7 @@ obj-$(CONFIG_KEYBOARD_AMIGA)		+= amikbd.o
 | 
				
			||||||
obj-$(CONFIG_KEYBOARD_ATARI)		+= atakbd.o
 | 
					obj-$(CONFIG_KEYBOARD_ATARI)		+= atakbd.o
 | 
				
			||||||
obj-$(CONFIG_KEYBOARD_ATKBD)		+= atkbd.o
 | 
					obj-$(CONFIG_KEYBOARD_ATKBD)		+= atkbd.o
 | 
				
			||||||
obj-$(CONFIG_KEYBOARD_BFIN)		+= bf54x-keys.o
 | 
					obj-$(CONFIG_KEYBOARD_BFIN)		+= bf54x-keys.o
 | 
				
			||||||
 | 
					obj-$(CONFIG_KEYBOARD_CAP1106)		+= cap1106.o
 | 
				
			||||||
obj-$(CONFIG_KEYBOARD_CLPS711X)		+= clps711x-keypad.o
 | 
					obj-$(CONFIG_KEYBOARD_CLPS711X)		+= clps711x-keypad.o
 | 
				
			||||||
obj-$(CONFIG_KEYBOARD_CROS_EC)		+= cros_ec_keyb.o
 | 
					obj-$(CONFIG_KEYBOARD_CROS_EC)		+= cros_ec_keyb.o
 | 
				
			||||||
obj-$(CONFIG_KEYBOARD_DAVINCI)		+= davinci_keyscan.o
 | 
					obj-$(CONFIG_KEYBOARD_DAVINCI)		+= davinci_keyscan.o
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										335
									
								
								drivers/input/keyboard/cap1106.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										335
									
								
								drivers/input/keyboard/cap1106.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,335 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Input driver for Microchip CAP1106, 6 channel capacitive touch sensor
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * http://www.microchip.com/wwwproducts/Devices.aspx?product=CAP1106
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * (c) 2014 Daniel Mack <linux@zonque.org>
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * 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/module.h>
 | 
				
			||||||
 | 
					#include <linux/interrupt.h>
 | 
				
			||||||
 | 
					#include <linux/input.h>
 | 
				
			||||||
 | 
					#include <linux/of_irq.h>
 | 
				
			||||||
 | 
					#include <linux/regmap.h>
 | 
				
			||||||
 | 
					#include <linux/i2c.h>
 | 
				
			||||||
 | 
					#include <linux/gpio/consumer.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define CAP1106_REG_MAIN_CONTROL	0x00
 | 
				
			||||||
 | 
					#define CAP1106_REG_MAIN_CONTROL_GAIN_SHIFT	(6)
 | 
				
			||||||
 | 
					#define CAP1106_REG_MAIN_CONTROL_GAIN_MASK	(0xc0)
 | 
				
			||||||
 | 
					#define CAP1106_REG_MAIN_CONTROL_DLSEEP		BIT(4)
 | 
				
			||||||
 | 
					#define CAP1106_REG_GENERAL_STATUS	0x02
 | 
				
			||||||
 | 
					#define CAP1106_REG_SENSOR_INPUT	0x03
 | 
				
			||||||
 | 
					#define CAP1106_REG_NOISE_FLAG_STATUS	0x0a
 | 
				
			||||||
 | 
					#define CAP1106_REG_SENOR_DELTA(X)	(0x10 + (X))
 | 
				
			||||||
 | 
					#define CAP1106_REG_SENSITIVITY_CONTROL	0x1f
 | 
				
			||||||
 | 
					#define CAP1106_REG_CONFIG		0x20
 | 
				
			||||||
 | 
					#define CAP1106_REG_SENSOR_ENABLE	0x21
 | 
				
			||||||
 | 
					#define CAP1106_REG_SENSOR_CONFIG	0x22
 | 
				
			||||||
 | 
					#define CAP1106_REG_SENSOR_CONFIG2	0x23
 | 
				
			||||||
 | 
					#define CAP1106_REG_SAMPLING_CONFIG	0x24
 | 
				
			||||||
 | 
					#define CAP1106_REG_CALIBRATION		0x25
 | 
				
			||||||
 | 
					#define CAP1106_REG_INT_ENABLE		0x26
 | 
				
			||||||
 | 
					#define CAP1106_REG_REPEAT_RATE		0x28
 | 
				
			||||||
 | 
					#define CAP1106_REG_MT_CONFIG		0x2a
 | 
				
			||||||
 | 
					#define CAP1106_REG_MT_PATTERN_CONFIG	0x2b
 | 
				
			||||||
 | 
					#define CAP1106_REG_MT_PATTERN		0x2d
 | 
				
			||||||
 | 
					#define CAP1106_REG_RECALIB_CONFIG	0x2f
 | 
				
			||||||
 | 
					#define CAP1106_REG_SENSOR_THRESH(X)	(0x30 + (X))
 | 
				
			||||||
 | 
					#define CAP1106_REG_SENSOR_NOISE_THRESH	0x38
 | 
				
			||||||
 | 
					#define CAP1106_REG_STANDBY_CHANNEL	0x40
 | 
				
			||||||
 | 
					#define CAP1106_REG_STANDBY_CONFIG	0x41
 | 
				
			||||||
 | 
					#define CAP1106_REG_STANDBY_SENSITIVITY	0x42
 | 
				
			||||||
 | 
					#define CAP1106_REG_STANDBY_THRESH	0x43
 | 
				
			||||||
 | 
					#define CAP1106_REG_CONFIG2		0x44
 | 
				
			||||||
 | 
					#define CAP1106_REG_SENSOR_BASE_CNT(X)	(0x50 + (X))
 | 
				
			||||||
 | 
					#define CAP1106_REG_SENSOR_CALIB	(0xb1 + (X))
 | 
				
			||||||
 | 
					#define CAP1106_REG_SENSOR_CALIB_LSB1	0xb9
 | 
				
			||||||
 | 
					#define CAP1106_REG_SENSOR_CALIB_LSB2	0xba
 | 
				
			||||||
 | 
					#define CAP1106_REG_PRODUCT_ID		0xfd
 | 
				
			||||||
 | 
					#define CAP1106_REG_MANUFACTURER_ID	0xfe
 | 
				
			||||||
 | 
					#define CAP1106_REG_REVISION		0xff
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define CAP1106_NUM_CHN 6
 | 
				
			||||||
 | 
					#define CAP1106_PRODUCT_ID	0x55
 | 
				
			||||||
 | 
					#define CAP1106_MANUFACTURER_ID	0x5d
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct cap1106_priv {
 | 
				
			||||||
 | 
						struct regmap *regmap;
 | 
				
			||||||
 | 
						struct input_dev *idev;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* config */
 | 
				
			||||||
 | 
						unsigned int keycodes[CAP1106_NUM_CHN];
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct reg_default cap1106_reg_defaults[] = {
 | 
				
			||||||
 | 
						{ CAP1106_REG_MAIN_CONTROL,		0x00 },
 | 
				
			||||||
 | 
						{ CAP1106_REG_GENERAL_STATUS,		0x00 },
 | 
				
			||||||
 | 
						{ CAP1106_REG_SENSOR_INPUT,		0x00 },
 | 
				
			||||||
 | 
						{ CAP1106_REG_NOISE_FLAG_STATUS,	0x00 },
 | 
				
			||||||
 | 
						{ CAP1106_REG_SENSITIVITY_CONTROL,	0x2f },
 | 
				
			||||||
 | 
						{ CAP1106_REG_CONFIG,			0x20 },
 | 
				
			||||||
 | 
						{ CAP1106_REG_SENSOR_ENABLE,		0x3f },
 | 
				
			||||||
 | 
						{ CAP1106_REG_SENSOR_CONFIG,		0xa4 },
 | 
				
			||||||
 | 
						{ CAP1106_REG_SENSOR_CONFIG2,		0x07 },
 | 
				
			||||||
 | 
						{ CAP1106_REG_SAMPLING_CONFIG,		0x39 },
 | 
				
			||||||
 | 
						{ CAP1106_REG_CALIBRATION,		0x00 },
 | 
				
			||||||
 | 
						{ CAP1106_REG_INT_ENABLE,		0x3f },
 | 
				
			||||||
 | 
						{ CAP1106_REG_REPEAT_RATE,		0x3f },
 | 
				
			||||||
 | 
						{ CAP1106_REG_MT_CONFIG,		0x80 },
 | 
				
			||||||
 | 
						{ CAP1106_REG_MT_PATTERN_CONFIG,	0x00 },
 | 
				
			||||||
 | 
						{ CAP1106_REG_MT_PATTERN,		0x3f },
 | 
				
			||||||
 | 
						{ CAP1106_REG_RECALIB_CONFIG,		0x8a },
 | 
				
			||||||
 | 
						{ CAP1106_REG_SENSOR_THRESH(0),		0x40 },
 | 
				
			||||||
 | 
						{ CAP1106_REG_SENSOR_THRESH(1),		0x40 },
 | 
				
			||||||
 | 
						{ CAP1106_REG_SENSOR_THRESH(2),		0x40 },
 | 
				
			||||||
 | 
						{ CAP1106_REG_SENSOR_THRESH(3),		0x40 },
 | 
				
			||||||
 | 
						{ CAP1106_REG_SENSOR_THRESH(4),		0x40 },
 | 
				
			||||||
 | 
						{ CAP1106_REG_SENSOR_THRESH(5),		0x40 },
 | 
				
			||||||
 | 
						{ CAP1106_REG_SENSOR_NOISE_THRESH,	0x01 },
 | 
				
			||||||
 | 
						{ CAP1106_REG_STANDBY_CHANNEL,		0x00 },
 | 
				
			||||||
 | 
						{ CAP1106_REG_STANDBY_CONFIG,		0x39 },
 | 
				
			||||||
 | 
						{ CAP1106_REG_STANDBY_SENSITIVITY,	0x02 },
 | 
				
			||||||
 | 
						{ CAP1106_REG_STANDBY_THRESH,		0x40 },
 | 
				
			||||||
 | 
						{ CAP1106_REG_CONFIG2,			0x40 },
 | 
				
			||||||
 | 
						{ CAP1106_REG_SENSOR_CALIB_LSB1,	0x00 },
 | 
				
			||||||
 | 
						{ CAP1106_REG_SENSOR_CALIB_LSB2,	0x00 },
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static bool cap1106_volatile_reg(struct device *dev, unsigned int reg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						switch (reg) {
 | 
				
			||||||
 | 
						case CAP1106_REG_MAIN_CONTROL:
 | 
				
			||||||
 | 
						case CAP1106_REG_SENSOR_INPUT:
 | 
				
			||||||
 | 
						case CAP1106_REG_SENOR_DELTA(0):
 | 
				
			||||||
 | 
						case CAP1106_REG_SENOR_DELTA(1):
 | 
				
			||||||
 | 
						case CAP1106_REG_SENOR_DELTA(2):
 | 
				
			||||||
 | 
						case CAP1106_REG_SENOR_DELTA(3):
 | 
				
			||||||
 | 
						case CAP1106_REG_SENOR_DELTA(4):
 | 
				
			||||||
 | 
						case CAP1106_REG_SENOR_DELTA(5):
 | 
				
			||||||
 | 
						case CAP1106_REG_PRODUCT_ID:
 | 
				
			||||||
 | 
						case CAP1106_REG_MANUFACTURER_ID:
 | 
				
			||||||
 | 
						case CAP1106_REG_REVISION:
 | 
				
			||||||
 | 
							return true;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct regmap_config cap1106_regmap_config = {
 | 
				
			||||||
 | 
						.reg_bits = 8,
 | 
				
			||||||
 | 
						.val_bits = 8,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						.max_register = CAP1106_REG_REVISION,
 | 
				
			||||||
 | 
						.reg_defaults = cap1106_reg_defaults,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						.num_reg_defaults = ARRAY_SIZE(cap1106_reg_defaults),
 | 
				
			||||||
 | 
						.cache_type = REGCACHE_RBTREE,
 | 
				
			||||||
 | 
						.volatile_reg = cap1106_volatile_reg,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static irqreturn_t cap1106_thread_func(int irq_num, void *data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct cap1106_priv *priv = data;
 | 
				
			||||||
 | 
						unsigned int status;
 | 
				
			||||||
 | 
						int ret, i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * Deassert interrupt. This needs to be done before reading the status
 | 
				
			||||||
 | 
						 * registers, which will not carry valid values otherwise.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						ret = regmap_update_bits(priv->regmap, CAP1106_REG_MAIN_CONTROL, 1, 0);
 | 
				
			||||||
 | 
						if (ret < 0)
 | 
				
			||||||
 | 
							goto out;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = regmap_read(priv->regmap, CAP1106_REG_SENSOR_INPUT, &status);
 | 
				
			||||||
 | 
						if (ret < 0)
 | 
				
			||||||
 | 
							goto out;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i < CAP1106_NUM_CHN; i++)
 | 
				
			||||||
 | 
							input_report_key(priv->idev, priv->keycodes[i],
 | 
				
			||||||
 | 
									 status & (1 << i));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						input_sync(priv->idev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					out:
 | 
				
			||||||
 | 
						return IRQ_HANDLED;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int cap1106_set_sleep(struct cap1106_priv *priv, bool sleep)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return regmap_update_bits(priv->regmap, CAP1106_REG_MAIN_CONTROL,
 | 
				
			||||||
 | 
									  CAP1106_REG_MAIN_CONTROL_DLSEEP,
 | 
				
			||||||
 | 
									  sleep ? CAP1106_REG_MAIN_CONTROL_DLSEEP : 0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int cap1106_input_open(struct input_dev *idev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct cap1106_priv *priv = input_get_drvdata(idev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return cap1106_set_sleep(priv, false);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void cap1106_input_close(struct input_dev *idev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct cap1106_priv *priv = input_get_drvdata(idev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						cap1106_set_sleep(priv, true);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int cap1106_i2c_probe(struct i2c_client *i2c_client,
 | 
				
			||||||
 | 
								     const struct i2c_device_id *id)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct device *dev = &i2c_client->dev;
 | 
				
			||||||
 | 
						struct cap1106_priv *priv;
 | 
				
			||||||
 | 
						struct device_node *node;
 | 
				
			||||||
 | 
						int i, error, irq, gain = 0;
 | 
				
			||||||
 | 
						unsigned int val, rev;
 | 
				
			||||||
 | 
						u32 gain32, keycodes[CAP1106_NUM_CHN];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
 | 
				
			||||||
 | 
						if (!priv)
 | 
				
			||||||
 | 
							return -ENOMEM;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						priv->regmap = devm_regmap_init_i2c(i2c_client, &cap1106_regmap_config);
 | 
				
			||||||
 | 
						if (IS_ERR(priv->regmap))
 | 
				
			||||||
 | 
							return PTR_ERR(priv->regmap);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						error = regmap_read(priv->regmap, CAP1106_REG_PRODUCT_ID, &val);
 | 
				
			||||||
 | 
						if (error)
 | 
				
			||||||
 | 
							return error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (val != CAP1106_PRODUCT_ID) {
 | 
				
			||||||
 | 
							dev_err(dev, "Product ID: Got 0x%02x, expected 0x%02x\n",
 | 
				
			||||||
 | 
								val, CAP1106_PRODUCT_ID);
 | 
				
			||||||
 | 
							return -ENODEV;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						error = regmap_read(priv->regmap, CAP1106_REG_MANUFACTURER_ID, &val);
 | 
				
			||||||
 | 
						if (error)
 | 
				
			||||||
 | 
							return error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (val != CAP1106_MANUFACTURER_ID) {
 | 
				
			||||||
 | 
							dev_err(dev, "Manufacturer ID: Got 0x%02x, expected 0x%02x\n",
 | 
				
			||||||
 | 
								val, CAP1106_MANUFACTURER_ID);
 | 
				
			||||||
 | 
							return -ENODEV;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						error = regmap_read(priv->regmap, CAP1106_REG_REVISION, &rev);
 | 
				
			||||||
 | 
						if (error < 0)
 | 
				
			||||||
 | 
							return error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dev_info(dev, "CAP1106 detected, revision 0x%02x\n", rev);
 | 
				
			||||||
 | 
						i2c_set_clientdata(i2c_client, priv);
 | 
				
			||||||
 | 
						node = dev->of_node;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!of_property_read_u32(node, "microchip,sensor-gain", &gain32)) {
 | 
				
			||||||
 | 
							if (is_power_of_2(gain32) && gain32 <= 8)
 | 
				
			||||||
 | 
								gain = ilog2(gain32);
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
								dev_err(dev, "Invalid sensor-gain value %d\n", gain32);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						BUILD_BUG_ON(ARRAY_SIZE(keycodes) != ARRAY_SIZE(priv->keycodes));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Provide some useful defaults */
 | 
				
			||||||
 | 
						for (i = 0; i < ARRAY_SIZE(keycodes); i++)
 | 
				
			||||||
 | 
							keycodes[i] = KEY_A + i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						of_property_read_u32_array(node, "linux,keycodes",
 | 
				
			||||||
 | 
									   keycodes, ARRAY_SIZE(keycodes));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i < ARRAY_SIZE(keycodes); i++)
 | 
				
			||||||
 | 
							priv->keycodes[i] = keycodes[i];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						error = regmap_update_bits(priv->regmap, CAP1106_REG_MAIN_CONTROL,
 | 
				
			||||||
 | 
									   CAP1106_REG_MAIN_CONTROL_GAIN_MASK,
 | 
				
			||||||
 | 
									   gain << CAP1106_REG_MAIN_CONTROL_GAIN_SHIFT);
 | 
				
			||||||
 | 
						if (error)
 | 
				
			||||||
 | 
							return error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Disable autorepeat. The Linux input system has its own handling. */
 | 
				
			||||||
 | 
						error = regmap_write(priv->regmap, CAP1106_REG_REPEAT_RATE, 0);
 | 
				
			||||||
 | 
						if (error)
 | 
				
			||||||
 | 
							return error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						priv->idev = devm_input_allocate_device(dev);
 | 
				
			||||||
 | 
						if (!priv->idev)
 | 
				
			||||||
 | 
							return -ENOMEM;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						priv->idev->name = "CAP1106 capacitive touch sensor";
 | 
				
			||||||
 | 
						priv->idev->id.bustype = BUS_I2C;
 | 
				
			||||||
 | 
						priv->idev->evbit[0] = BIT_MASK(EV_KEY);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (of_property_read_bool(node, "autorepeat"))
 | 
				
			||||||
 | 
							__set_bit(EV_REP, priv->idev->evbit);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i < CAP1106_NUM_CHN; i++)
 | 
				
			||||||
 | 
							__set_bit(priv->keycodes[i], priv->idev->keybit);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						priv->idev->id.vendor = CAP1106_MANUFACTURER_ID;
 | 
				
			||||||
 | 
						priv->idev->id.product = CAP1106_PRODUCT_ID;
 | 
				
			||||||
 | 
						priv->idev->id.version = rev;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						priv->idev->open = cap1106_input_open;
 | 
				
			||||||
 | 
						priv->idev->close = cap1106_input_close;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						input_set_drvdata(priv->idev, priv);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * Put the device in deep sleep mode for now.
 | 
				
			||||||
 | 
						 * ->open() will bring it back once the it is actually needed.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						cap1106_set_sleep(priv, true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						error = input_register_device(priv->idev);
 | 
				
			||||||
 | 
						if (error)
 | 
				
			||||||
 | 
							return error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						irq = irq_of_parse_and_map(node, 0);
 | 
				
			||||||
 | 
						if (!irq) {
 | 
				
			||||||
 | 
							dev_err(dev, "Unable to parse or map IRQ\n");
 | 
				
			||||||
 | 
							return -ENXIO;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						error = devm_request_threaded_irq(dev, irq, NULL, cap1106_thread_func,
 | 
				
			||||||
 | 
										  IRQF_ONESHOT, dev_name(dev), priv);
 | 
				
			||||||
 | 
						if (error)
 | 
				
			||||||
 | 
							return error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct of_device_id cap1106_dt_ids[] = {
 | 
				
			||||||
 | 
						{ .compatible = "microchip,cap1106", },
 | 
				
			||||||
 | 
						{}
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					MODULE_DEVICE_TABLE(of, cap1106_dt_ids);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct i2c_device_id cap1106_i2c_ids[] = {
 | 
				
			||||||
 | 
						{ "cap1106", 0 },
 | 
				
			||||||
 | 
						{}
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					MODULE_DEVICE_TABLE(i2c, cap1106_i2c_ids);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct i2c_driver cap1106_i2c_driver = {
 | 
				
			||||||
 | 
						.driver = {
 | 
				
			||||||
 | 
							.name	= "cap1106",
 | 
				
			||||||
 | 
							.owner	= THIS_MODULE,
 | 
				
			||||||
 | 
							.of_match_table = cap1106_dt_ids,
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						.id_table	= cap1106_i2c_ids,
 | 
				
			||||||
 | 
						.probe		= cap1106_i2c_probe,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module_i2c_driver(cap1106_i2c_driver);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					MODULE_ALIAS("platform:cap1106");
 | 
				
			||||||
 | 
					MODULE_DESCRIPTION("Microchip CAP1106 driver");
 | 
				
			||||||
 | 
					MODULE_AUTHOR("Daniel Mack <linux@zonque.org>");
 | 
				
			||||||
 | 
					MODULE_LICENSE("GPL v2");
 | 
				
			||||||
| 
						 | 
					@ -531,8 +531,7 @@ static int imx_keypad_probe(struct platform_device *pdev)
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_PM_SLEEP
 | 
					static int __maybe_unused imx_kbd_suspend(struct device *dev)
 | 
				
			||||||
static int imx_kbd_suspend(struct device *dev)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct platform_device *pdev = to_platform_device(dev);
 | 
						struct platform_device *pdev = to_platform_device(dev);
 | 
				
			||||||
	struct imx_keypad *kbd = platform_get_drvdata(pdev);
 | 
						struct imx_keypad *kbd = platform_get_drvdata(pdev);
 | 
				
			||||||
| 
						 | 
					@ -552,7 +551,7 @@ static int imx_kbd_suspend(struct device *dev)
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int imx_kbd_resume(struct device *dev)
 | 
					static int __maybe_unused imx_kbd_resume(struct device *dev)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct platform_device *pdev = to_platform_device(dev);
 | 
						struct platform_device *pdev = to_platform_device(dev);
 | 
				
			||||||
	struct imx_keypad *kbd = platform_get_drvdata(pdev);
 | 
						struct imx_keypad *kbd = platform_get_drvdata(pdev);
 | 
				
			||||||
| 
						 | 
					@ -575,7 +574,6 @@ err_clk:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
static SIMPLE_DEV_PM_OPS(imx_kbd_pm_ops, imx_kbd_suspend, imx_kbd_resume);
 | 
					static SIMPLE_DEV_PM_OPS(imx_kbd_pm_ops, imx_kbd_suspend, imx_kbd_resume);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -203,12 +203,17 @@ static int max7359_probe(struct i2c_client *client,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dev_dbg(&client->dev, "keys FIFO is 0x%02x\n", ret);
 | 
						dev_dbg(&client->dev, "keys FIFO is 0x%02x\n", ret);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	keypad = kzalloc(sizeof(struct max7359_keypad), GFP_KERNEL);
 | 
						keypad = devm_kzalloc(&client->dev, sizeof(struct max7359_keypad),
 | 
				
			||||||
	input_dev = input_allocate_device();
 | 
								      GFP_KERNEL);
 | 
				
			||||||
	if (!keypad || !input_dev) {
 | 
						if (!keypad) {
 | 
				
			||||||
		dev_err(&client->dev, "failed to allocate memory\n");
 | 
							dev_err(&client->dev, "failed to allocate memory\n");
 | 
				
			||||||
		error = -ENOMEM;
 | 
							return -ENOMEM;
 | 
				
			||||||
		goto failed_free_mem;
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						input_dev = devm_input_allocate_device(&client->dev);
 | 
				
			||||||
 | 
						if (!input_dev) {
 | 
				
			||||||
 | 
							dev_err(&client->dev, "failed to allocate input device\n");
 | 
				
			||||||
 | 
							return -ENOMEM;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	keypad->client = client;
 | 
						keypad->client = client;
 | 
				
			||||||
| 
						 | 
					@ -230,19 +235,20 @@ static int max7359_probe(struct i2c_client *client,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	max7359_build_keycode(keypad, keymap_data);
 | 
						max7359_build_keycode(keypad, keymap_data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	error = request_threaded_irq(client->irq, NULL, max7359_interrupt,
 | 
						error = devm_request_threaded_irq(&client->dev, client->irq, NULL,
 | 
				
			||||||
 | 
										  max7359_interrupt,
 | 
				
			||||||
					  IRQF_TRIGGER_LOW | IRQF_ONESHOT,
 | 
										  IRQF_TRIGGER_LOW | IRQF_ONESHOT,
 | 
				
			||||||
					  client->name, keypad);
 | 
										  client->name, keypad);
 | 
				
			||||||
	if (error) {
 | 
						if (error) {
 | 
				
			||||||
		dev_err(&client->dev, "failed to register interrupt\n");
 | 
							dev_err(&client->dev, "failed to register interrupt\n");
 | 
				
			||||||
		goto failed_free_mem;
 | 
							return error;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Register the input device */
 | 
						/* Register the input device */
 | 
				
			||||||
	error = input_register_device(input_dev);
 | 
						error = input_register_device(input_dev);
 | 
				
			||||||
	if (error) {
 | 
						if (error) {
 | 
				
			||||||
		dev_err(&client->dev, "failed to register input device\n");
 | 
							dev_err(&client->dev, "failed to register input device\n");
 | 
				
			||||||
		goto failed_free_irq;
 | 
							return error;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Initialize MAX7359 */
 | 
						/* Initialize MAX7359 */
 | 
				
			||||||
| 
						 | 
					@ -251,24 +257,6 @@ static int max7359_probe(struct i2c_client *client,
 | 
				
			||||||
	i2c_set_clientdata(client, keypad);
 | 
						i2c_set_clientdata(client, keypad);
 | 
				
			||||||
	device_init_wakeup(&client->dev, 1);
 | 
						device_init_wakeup(&client->dev, 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
failed_free_irq:
 | 
					 | 
				
			||||||
	free_irq(client->irq, keypad);
 | 
					 | 
				
			||||||
failed_free_mem:
 | 
					 | 
				
			||||||
	input_free_device(input_dev);
 | 
					 | 
				
			||||||
	kfree(keypad);
 | 
					 | 
				
			||||||
	return error;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int max7359_remove(struct i2c_client *client)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct max7359_keypad *keypad = i2c_get_clientdata(client);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	free_irq(client->irq, keypad);
 | 
					 | 
				
			||||||
	input_unregister_device(keypad->input_dev);
 | 
					 | 
				
			||||||
	kfree(keypad);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -313,7 +301,6 @@ static struct i2c_driver max7359_i2c_driver = {
 | 
				
			||||||
		.pm   = &max7359_pm,
 | 
							.pm   = &max7359_pm,
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
	.probe		= max7359_probe,
 | 
						.probe		= max7359_probe,
 | 
				
			||||||
	.remove		= max7359_remove,
 | 
					 | 
				
			||||||
	.id_table	= max7359_ids,
 | 
						.id_table	= max7359_ids,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -392,7 +392,6 @@ static void keyspan_irq_recv(struct urb *urb)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		goto resubmit;
 | 
							goto resubmit;
 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (debug)
 | 
						if (debug)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -83,6 +83,9 @@ soc_button_device_create(struct pnp_dev *pdev,
 | 
				
			||||||
				       sizeof(*gpio_keys_pdata) +
 | 
									       sizeof(*gpio_keys_pdata) +
 | 
				
			||||||
					sizeof(*gpio_keys) * MAX_NBUTTONS,
 | 
										sizeof(*gpio_keys) * MAX_NBUTTONS,
 | 
				
			||||||
				       GFP_KERNEL);
 | 
									       GFP_KERNEL);
 | 
				
			||||||
 | 
						if (!gpio_keys_pdata)
 | 
				
			||||||
 | 
							return ERR_PTR(-ENOMEM);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	gpio_keys = (void *)(gpio_keys_pdata + 1);
 | 
						gpio_keys = (void *)(gpio_keys_pdata + 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (info = button_info; info->name; info++) {
 | 
						for (info = button_info; info->name; info++) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -311,7 +311,14 @@ static int uinput_open(struct inode *inode, struct file *file)
 | 
				
			||||||
static int uinput_validate_absbits(struct input_dev *dev)
 | 
					static int uinput_validate_absbits(struct input_dev *dev)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	unsigned int cnt;
 | 
						unsigned int cnt;
 | 
				
			||||||
	int retval = 0;
 | 
						int nslot;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!test_bit(EV_ABS, dev->evbit))
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * Check if absmin/absmax/absfuzz/absflat are sane.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (cnt = 0; cnt < ABS_CNT; cnt++) {
 | 
						for (cnt = 0; cnt < ABS_CNT; cnt++) {
 | 
				
			||||||
		int min, max;
 | 
							int min, max;
 | 
				
			||||||
| 
						 | 
					@ -327,8 +334,7 @@ static int uinput_validate_absbits(struct input_dev *dev)
 | 
				
			||||||
				UINPUT_NAME, cnt,
 | 
									UINPUT_NAME, cnt,
 | 
				
			||||||
				input_abs_get_min(dev, cnt),
 | 
									input_abs_get_min(dev, cnt),
 | 
				
			||||||
				input_abs_get_max(dev, cnt));
 | 
									input_abs_get_max(dev, cnt));
 | 
				
			||||||
			retval = -EINVAL;
 | 
								return -EINVAL;
 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (input_abs_get_flat(dev, cnt) >
 | 
							if (input_abs_get_flat(dev, cnt) >
 | 
				
			||||||
| 
						 | 
					@ -340,11 +346,18 @@ static int uinput_validate_absbits(struct input_dev *dev)
 | 
				
			||||||
				input_abs_get_flat(dev, cnt),
 | 
									input_abs_get_flat(dev, cnt),
 | 
				
			||||||
				input_abs_get_min(dev, cnt),
 | 
									input_abs_get_min(dev, cnt),
 | 
				
			||||||
				input_abs_get_max(dev, cnt));
 | 
									input_abs_get_max(dev, cnt));
 | 
				
			||||||
			retval = -EINVAL;
 | 
								return -EINVAL;
 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return retval;
 | 
					
 | 
				
			||||||
 | 
						if (test_bit(ABS_MT_SLOT, dev->absbit)) {
 | 
				
			||||||
 | 
							nslot = input_abs_get_max(dev, ABS_MT_SLOT) + 1;
 | 
				
			||||||
 | 
							input_mt_init_slots(dev, nslot, 0);
 | 
				
			||||||
 | 
						} else if (test_bit(ABS_MT_POSITION_X, dev->absbit)) {
 | 
				
			||||||
 | 
							input_set_events_per_packet(dev, 60);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int uinput_allocate_device(struct uinput_device *udev)
 | 
					static int uinput_allocate_device(struct uinput_device *udev)
 | 
				
			||||||
| 
						 | 
					@ -410,19 +423,9 @@ static int uinput_setup_device(struct uinput_device *udev,
 | 
				
			||||||
		input_abs_set_flat(dev, i, user_dev->absflat[i]);
 | 
							input_abs_set_flat(dev, i, user_dev->absflat[i]);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* check if absmin/absmax/absfuzz/absflat are filled as
 | 
					 | 
				
			||||||
	 * told in Documentation/input/input-programming.txt */
 | 
					 | 
				
			||||||
	if (test_bit(EV_ABS, dev->evbit)) {
 | 
					 | 
				
			||||||
	retval = uinput_validate_absbits(dev);
 | 
						retval = uinput_validate_absbits(dev);
 | 
				
			||||||
	if (retval < 0)
 | 
						if (retval < 0)
 | 
				
			||||||
		goto exit;
 | 
							goto exit;
 | 
				
			||||||
		if (test_bit(ABS_MT_SLOT, dev->absbit)) {
 | 
					 | 
				
			||||||
			int nslot = input_abs_get_max(dev, ABS_MT_SLOT) + 1;
 | 
					 | 
				
			||||||
			input_mt_init_slots(dev, nslot, 0);
 | 
					 | 
				
			||||||
		} else if (test_bit(ABS_MT_POSITION_X, dev->absbit)) {
 | 
					 | 
				
			||||||
			input_set_events_per_packet(dev, 60);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	udev->state = UIST_SETUP_COMPLETE;
 | 
						udev->state = UIST_SETUP_COMPLETE;
 | 
				
			||||||
	retval = count;
 | 
						retval = count;
 | 
				
			||||||
| 
						 | 
					@ -720,6 +723,12 @@ static long uinput_ioctl_handler(struct file *file, unsigned int cmd,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	switch (cmd) {
 | 
						switch (cmd) {
 | 
				
			||||||
 | 
							case UI_GET_VERSION:
 | 
				
			||||||
 | 
								if (put_user(UINPUT_VERSION,
 | 
				
			||||||
 | 
									     (unsigned int __user *)p))
 | 
				
			||||||
 | 
									retval = -EFAULT;
 | 
				
			||||||
 | 
								goto out;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		case UI_DEV_CREATE:
 | 
							case UI_DEV_CREATE:
 | 
				
			||||||
			retval = uinput_create_device(udev);
 | 
								retval = uinput_create_device(udev);
 | 
				
			||||||
			goto out;
 | 
								goto out;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -99,6 +99,8 @@ static const struct alps_nibble_commands alps_v6_nibble_commands[] = {
 | 
				
			||||||
#define ALPS_FOUR_BUTTONS	0x40	/* 4 direction button present */
 | 
					#define ALPS_FOUR_BUTTONS	0x40	/* 4 direction button present */
 | 
				
			||||||
#define ALPS_PS2_INTERLEAVED	0x80	/* 3-byte PS/2 packet interleaved with
 | 
					#define ALPS_PS2_INTERLEAVED	0x80	/* 3-byte PS/2 packet interleaved with
 | 
				
			||||||
					   6-byte ALPS packet */
 | 
										   6-byte ALPS packet */
 | 
				
			||||||
 | 
					#define ALPS_IS_RUSHMORE	0x100	/* device is a rushmore */
 | 
				
			||||||
 | 
					#define ALPS_BUTTONPAD		0x200	/* device is a clickpad */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const struct alps_model_info alps_model_data[] = {
 | 
					static const struct alps_model_info alps_model_data[] = {
 | 
				
			||||||
	{ { 0x32, 0x02, 0x14 },	0x00, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT },	/* Toshiba Salellite Pro M10 */
 | 
						{ { 0x32, 0x02, 0x14 },	0x00, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT },	/* Toshiba Salellite Pro M10 */
 | 
				
			||||||
| 
						 | 
					@ -281,11 +283,10 @@ static void alps_process_packet_v1_v2(struct psmouse *psmouse)
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * The bitmaps don't have enough data to track fingers, so this function
 | 
					 * The bitmaps don't have enough data to track fingers, so this function
 | 
				
			||||||
 * only generates points representing a bounding box of at most two contacts.
 | 
					 * only generates points representing a bounding box of at most two contacts.
 | 
				
			||||||
 * These two points are returned in x1, y1, x2, and y2.
 | 
					 * These two points are returned in fields->mt.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static void alps_process_bitmap_dolphin(struct alps_data *priv,
 | 
					static void alps_process_bitmap_dolphin(struct alps_data *priv,
 | 
				
			||||||
					struct alps_fields *fields,
 | 
										struct alps_fields *fields)
 | 
				
			||||||
					int *x1, int *y1, int *x2, int *y2)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int box_middle_x, box_middle_y;
 | 
						int box_middle_x, box_middle_y;
 | 
				
			||||||
	unsigned int x_map, y_map;
 | 
						unsigned int x_map, y_map;
 | 
				
			||||||
| 
						 | 
					@ -308,8 +309,6 @@ static void alps_process_bitmap_dolphin(struct alps_data *priv,
 | 
				
			||||||
	if (x_msb > priv->x_bits || y_msb > priv->y_bits)
 | 
						if (x_msb > priv->x_bits || y_msb > priv->y_bits)
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	*x1 = *y1 = *x2 = *y2 = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (fields->fingers > 1) {
 | 
						if (fields->fingers > 1) {
 | 
				
			||||||
		start_bit = priv->x_bits - x_msb;
 | 
							start_bit = priv->x_bits - x_msb;
 | 
				
			||||||
		end_bit = priv->x_bits - x_lsb;
 | 
							end_bit = priv->x_bits - x_lsb;
 | 
				
			||||||
| 
						 | 
					@ -320,10 +319,35 @@ static void alps_process_bitmap_dolphin(struct alps_data *priv,
 | 
				
			||||||
		end_bit = y_msb - 1;
 | 
							end_bit = y_msb - 1;
 | 
				
			||||||
		box_middle_y = (priv->y_max * (start_bit + end_bit)) /
 | 
							box_middle_y = (priv->y_max * (start_bit + end_bit)) /
 | 
				
			||||||
				(2 * (priv->y_bits - 1));
 | 
									(2 * (priv->y_bits - 1));
 | 
				
			||||||
		*x1 = fields->x;
 | 
							fields->mt[0] = fields->st;
 | 
				
			||||||
		*y1 = fields->y;
 | 
							fields->mt[1].x = 2 * box_middle_x - fields->mt[0].x;
 | 
				
			||||||
		*x2 = 2 * box_middle_x - *x1;
 | 
							fields->mt[1].y = 2 * box_middle_y - fields->mt[0].y;
 | 
				
			||||||
		*y2 = 2 * box_middle_y - *y1;
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void alps_get_bitmap_points(unsigned int map,
 | 
				
			||||||
 | 
									   struct alps_bitmap_point *low,
 | 
				
			||||||
 | 
									   struct alps_bitmap_point *high,
 | 
				
			||||||
 | 
									   int *fingers)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct alps_bitmap_point *point;
 | 
				
			||||||
 | 
						int i, bit, prev_bit = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						point = low;
 | 
				
			||||||
 | 
						for (i = 0; map != 0; i++, map >>= 1) {
 | 
				
			||||||
 | 
							bit = map & 1;
 | 
				
			||||||
 | 
							if (bit) {
 | 
				
			||||||
 | 
								if (!prev_bit) {
 | 
				
			||||||
 | 
									point->start_bit = i;
 | 
				
			||||||
 | 
									point->num_bits = 0;
 | 
				
			||||||
 | 
									(*fingers)++;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								point->num_bits++;
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								if (prev_bit)
 | 
				
			||||||
 | 
									point = high;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							prev_bit = bit;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -334,71 +358,21 @@ static void alps_process_bitmap_dolphin(struct alps_data *priv,
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * The bitmaps don't have enough data to track fingers, so this function
 | 
					 * The bitmaps don't have enough data to track fingers, so this function
 | 
				
			||||||
 * only generates points representing a bounding box of all contacts.
 | 
					 * only generates points representing a bounding box of all contacts.
 | 
				
			||||||
 * These points are returned in x1, y1, x2, and y2 when the return value
 | 
					 * These points are returned in fields->mt when the return value
 | 
				
			||||||
 * is greater than 0.
 | 
					 * is greater than 0.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static int alps_process_bitmap(struct alps_data *priv,
 | 
					static int alps_process_bitmap(struct alps_data *priv,
 | 
				
			||||||
			       unsigned int x_map, unsigned int y_map,
 | 
								       struct alps_fields *fields)
 | 
				
			||||||
			       int *x1, int *y1, int *x2, int *y2)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct alps_bitmap_point {
 | 
						int i, fingers_x = 0, fingers_y = 0, fingers;
 | 
				
			||||||
		int start_bit;
 | 
					 | 
				
			||||||
		int num_bits;
 | 
					 | 
				
			||||||
	};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	int fingers_x = 0, fingers_y = 0, fingers;
 | 
					 | 
				
			||||||
	int i, bit, prev_bit;
 | 
					 | 
				
			||||||
	struct alps_bitmap_point x_low = {0,}, x_high = {0,};
 | 
						struct alps_bitmap_point x_low = {0,}, x_high = {0,};
 | 
				
			||||||
	struct alps_bitmap_point y_low = {0,}, y_high = {0,};
 | 
						struct alps_bitmap_point y_low = {0,}, y_high = {0,};
 | 
				
			||||||
	struct alps_bitmap_point *point;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!x_map || !y_map)
 | 
						if (!fields->x_map || !fields->y_map)
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	*x1 = *y1 = *x2 = *y2 = 0;
 | 
						alps_get_bitmap_points(fields->x_map, &x_low, &x_high, &fingers_x);
 | 
				
			||||||
 | 
						alps_get_bitmap_points(fields->y_map, &y_low, &y_high, &fingers_y);
 | 
				
			||||||
	prev_bit = 0;
 | 
					 | 
				
			||||||
	point = &x_low;
 | 
					 | 
				
			||||||
	for (i = 0; x_map != 0; i++, x_map >>= 1) {
 | 
					 | 
				
			||||||
		bit = x_map & 1;
 | 
					 | 
				
			||||||
		if (bit) {
 | 
					 | 
				
			||||||
			if (!prev_bit) {
 | 
					 | 
				
			||||||
				point->start_bit = i;
 | 
					 | 
				
			||||||
				fingers_x++;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			point->num_bits++;
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			if (prev_bit)
 | 
					 | 
				
			||||||
				point = &x_high;
 | 
					 | 
				
			||||||
			else
 | 
					 | 
				
			||||||
				point->num_bits = 0;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		prev_bit = bit;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/*
 | 
					 | 
				
			||||||
	 * y bitmap is reversed for what we need (lower positions are in
 | 
					 | 
				
			||||||
	 * higher bits), so we process from the top end.
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	y_map = y_map << (sizeof(y_map) * BITS_PER_BYTE - priv->y_bits);
 | 
					 | 
				
			||||||
	prev_bit = 0;
 | 
					 | 
				
			||||||
	point = &y_low;
 | 
					 | 
				
			||||||
	for (i = 0; y_map != 0; i++, y_map <<= 1) {
 | 
					 | 
				
			||||||
		bit = y_map & (1 << (sizeof(y_map) * BITS_PER_BYTE - 1));
 | 
					 | 
				
			||||||
		if (bit) {
 | 
					 | 
				
			||||||
			if (!prev_bit) {
 | 
					 | 
				
			||||||
				point->start_bit = i;
 | 
					 | 
				
			||||||
				fingers_y++;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			point->num_bits++;
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			if (prev_bit)
 | 
					 | 
				
			||||||
				point = &y_high;
 | 
					 | 
				
			||||||
			else
 | 
					 | 
				
			||||||
				point->num_bits = 0;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		prev_bit = bit;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * Fingers can overlap, so we use the maximum count of fingers
 | 
						 * Fingers can overlap, so we use the maximum count of fingers
 | 
				
			||||||
| 
						 | 
					@ -407,58 +381,91 @@ static int alps_process_bitmap(struct alps_data *priv,
 | 
				
			||||||
	fingers = max(fingers_x, fingers_y);
 | 
						fingers = max(fingers_x, fingers_y);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * If total fingers is > 1 but either axis reports only a single
 | 
						 * If an axis reports only a single contact, we have overlapping or
 | 
				
			||||||
	 * contact, we have overlapping or adjacent fingers. For the
 | 
						 * adjacent fingers. Divide the single contact between the two points.
 | 
				
			||||||
	 * purposes of creating a bounding box, divide the single contact
 | 
					 | 
				
			||||||
	 * (roughly) equally between the two points.
 | 
					 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	if (fingers > 1) {
 | 
					 | 
				
			||||||
	if (fingers_x == 1) {
 | 
						if (fingers_x == 1) {
 | 
				
			||||||
			i = x_low.num_bits / 2;
 | 
							i = (x_low.num_bits - 1) / 2;
 | 
				
			||||||
		x_low.num_bits = x_low.num_bits - i;
 | 
							x_low.num_bits = x_low.num_bits - i;
 | 
				
			||||||
		x_high.start_bit = x_low.start_bit + i;
 | 
							x_high.start_bit = x_low.start_bit + i;
 | 
				
			||||||
		x_high.num_bits = max(i, 1);
 | 
							x_high.num_bits = max(i, 1);
 | 
				
			||||||
		} else if (fingers_y == 1) {
 | 
						}
 | 
				
			||||||
			i = y_low.num_bits / 2;
 | 
						if (fingers_y == 1) {
 | 
				
			||||||
 | 
							i = (y_low.num_bits - 1) / 2;
 | 
				
			||||||
		y_low.num_bits = y_low.num_bits - i;
 | 
							y_low.num_bits = y_low.num_bits - i;
 | 
				
			||||||
		y_high.start_bit = y_low.start_bit + i;
 | 
							y_high.start_bit = y_low.start_bit + i;
 | 
				
			||||||
		y_high.num_bits = max(i, 1);
 | 
							y_high.num_bits = max(i, 1);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	*x1 = (priv->x_max * (2 * x_low.start_bit + x_low.num_bits - 1)) /
 | 
						fields->mt[0].x =
 | 
				
			||||||
 | 
							(priv->x_max * (2 * x_low.start_bit + x_low.num_bits - 1)) /
 | 
				
			||||||
		(2 * (priv->x_bits - 1));
 | 
							(2 * (priv->x_bits - 1));
 | 
				
			||||||
	*y1 = (priv->y_max * (2 * y_low.start_bit + y_low.num_bits - 1)) /
 | 
						fields->mt[0].y =
 | 
				
			||||||
 | 
							(priv->y_max * (2 * y_low.start_bit + y_low.num_bits - 1)) /
 | 
				
			||||||
		(2 * (priv->y_bits - 1));
 | 
							(2 * (priv->y_bits - 1));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (fingers > 1) {
 | 
						fields->mt[1].x =
 | 
				
			||||||
		*x2 = (priv->x_max *
 | 
							(priv->x_max * (2 * x_high.start_bit + x_high.num_bits - 1)) /
 | 
				
			||||||
		       (2 * x_high.start_bit + x_high.num_bits - 1)) /
 | 
					 | 
				
			||||||
		(2 * (priv->x_bits - 1));
 | 
							(2 * (priv->x_bits - 1));
 | 
				
			||||||
		*y2 = (priv->y_max *
 | 
						fields->mt[1].y =
 | 
				
			||||||
		       (2 * y_high.start_bit + y_high.num_bits - 1)) /
 | 
							(priv->y_max * (2 * y_high.start_bit + y_high.num_bits - 1)) /
 | 
				
			||||||
		(2 * (priv->y_bits - 1));
 | 
							(2 * (priv->y_bits - 1));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* y-bitmap order is reversed, except on rushmore */
 | 
				
			||||||
 | 
						if (!(priv->flags & ALPS_IS_RUSHMORE)) {
 | 
				
			||||||
 | 
							fields->mt[0].y = priv->y_max - fields->mt[0].y;
 | 
				
			||||||
 | 
							fields->mt[1].y = priv->y_max - fields->mt[1].y;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return fingers;
 | 
						return fingers;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void alps_set_slot(struct input_dev *dev, int slot, bool active,
 | 
					static void alps_set_slot(struct input_dev *dev, int slot, int x, int y)
 | 
				
			||||||
			  int x, int y)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	input_mt_slot(dev, slot);
 | 
						input_mt_slot(dev, slot);
 | 
				
			||||||
	input_mt_report_slot_state(dev, MT_TOOL_FINGER, active);
 | 
						input_mt_report_slot_state(dev, MT_TOOL_FINGER, true);
 | 
				
			||||||
	if (active) {
 | 
					 | 
				
			||||||
	input_report_abs(dev, ABS_MT_POSITION_X, x);
 | 
						input_report_abs(dev, ABS_MT_POSITION_X, x);
 | 
				
			||||||
	input_report_abs(dev, ABS_MT_POSITION_Y, y);
 | 
						input_report_abs(dev, ABS_MT_POSITION_Y, y);
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void alps_report_semi_mt_data(struct input_dev *dev, int num_fingers,
 | 
					static void alps_report_mt_data(struct psmouse *psmouse, int n)
 | 
				
			||||||
				     int x1, int y1, int x2, int y2)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	alps_set_slot(dev, 0, num_fingers != 0, x1, y1);
 | 
						struct alps_data *priv = psmouse->private;
 | 
				
			||||||
	alps_set_slot(dev, 1, num_fingers == 2, x2, y2);
 | 
						struct input_dev *dev = psmouse->dev;
 | 
				
			||||||
 | 
						struct alps_fields *f = &priv->f;
 | 
				
			||||||
 | 
						int i, slot[MAX_TOUCHES];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						input_mt_assign_slots(dev, slot, f->mt, n);
 | 
				
			||||||
 | 
						for (i = 0; i < n; i++)
 | 
				
			||||||
 | 
							alps_set_slot(dev, slot[i], f->mt[i].x, f->mt[i].y);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						input_mt_sync_frame(dev);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void alps_report_semi_mt_data(struct psmouse *psmouse, int fingers)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct alps_data *priv = psmouse->private;
 | 
				
			||||||
 | 
						struct input_dev *dev = psmouse->dev;
 | 
				
			||||||
 | 
						struct alps_fields *f = &priv->f;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Use st data when we don't have mt data */
 | 
				
			||||||
 | 
						if (fingers < 2) {
 | 
				
			||||||
 | 
							f->mt[0].x = f->st.x;
 | 
				
			||||||
 | 
							f->mt[0].y = f->st.y;
 | 
				
			||||||
 | 
							fingers = f->pressure > 0 ? 1 : 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						alps_report_mt_data(psmouse, (fingers <= 2) ? fingers : 2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						input_mt_report_finger_count(dev, fingers);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						input_report_key(dev, BTN_LEFT, f->left);
 | 
				
			||||||
 | 
						input_report_key(dev, BTN_RIGHT, f->right);
 | 
				
			||||||
 | 
						input_report_key(dev, BTN_MIDDLE, f->middle);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						input_report_abs(dev, ABS_PRESSURE, f->pressure);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						input_sync(dev);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void alps_process_trackstick_packet_v3(struct psmouse *psmouse)
 | 
					static void alps_process_trackstick_packet_v3(struct psmouse *psmouse)
 | 
				
			||||||
| 
						 | 
					@ -532,7 +539,7 @@ static void alps_decode_buttons_v3(struct alps_fields *f, unsigned char *p)
 | 
				
			||||||
	f->ts_middle = !!(p[3] & 0x40);
 | 
						f->ts_middle = !!(p[3] & 0x40);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void alps_decode_pinnacle(struct alps_fields *f, unsigned char *p,
 | 
					static int alps_decode_pinnacle(struct alps_fields *f, unsigned char *p,
 | 
				
			||||||
				 struct psmouse *psmouse)
 | 
									 struct psmouse *psmouse)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	f->first_mp = !!(p[4] & 0x40);
 | 
						f->first_mp = !!(p[4] & 0x40);
 | 
				
			||||||
| 
						 | 
					@ -546,24 +553,31 @@ static void alps_decode_pinnacle(struct alps_fields *f, unsigned char *p,
 | 
				
			||||||
		   ((p[2] & 0x7f) << 1) |
 | 
							   ((p[2] & 0x7f) << 1) |
 | 
				
			||||||
		   (p[4] & 0x01);
 | 
							   (p[4] & 0x01);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	f->x = ((p[1] & 0x7f) << 4) | ((p[4] & 0x30) >> 2) |
 | 
						f->st.x = ((p[1] & 0x7f) << 4) | ((p[4] & 0x30) >> 2) |
 | 
				
			||||||
	       ((p[0] & 0x30) >> 4);
 | 
						       ((p[0] & 0x30) >> 4);
 | 
				
			||||||
	f->y = ((p[2] & 0x7f) << 4) | (p[4] & 0x0f);
 | 
						f->st.y = ((p[2] & 0x7f) << 4) | (p[4] & 0x0f);
 | 
				
			||||||
	f->z = p[5] & 0x7f;
 | 
						f->pressure = p[5] & 0x7f;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	alps_decode_buttons_v3(f, p);
 | 
						alps_decode_buttons_v3(f, p);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void alps_decode_rushmore(struct alps_fields *f, unsigned char *p,
 | 
					static int alps_decode_rushmore(struct alps_fields *f, unsigned char *p,
 | 
				
			||||||
				 struct psmouse *psmouse)
 | 
									 struct psmouse *psmouse)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	alps_decode_pinnacle(f, p, psmouse);
 | 
						alps_decode_pinnacle(f, p, psmouse);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Rushmore's packet decode has a bit difference with Pinnacle's */
 | 
				
			||||||
 | 
						f->is_mp = !!(p[5] & 0x40);
 | 
				
			||||||
 | 
						f->fingers = max((p[5] & 0x3), ((p[5] >> 2) & 0x3)) + 1;
 | 
				
			||||||
	f->x_map |= (p[5] & 0x10) << 11;
 | 
						f->x_map |= (p[5] & 0x10) << 11;
 | 
				
			||||||
	f->y_map |= (p[5] & 0x20) << 6;
 | 
						f->y_map |= (p[5] & 0x20) << 6;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void alps_decode_dolphin(struct alps_fields *f, unsigned char *p,
 | 
					static int alps_decode_dolphin(struct alps_fields *f, unsigned char *p,
 | 
				
			||||||
				struct psmouse *psmouse)
 | 
									struct psmouse *psmouse)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	u64 palm_data = 0;
 | 
						u64 palm_data = 0;
 | 
				
			||||||
| 
						 | 
					@ -573,9 +587,9 @@ static void alps_decode_dolphin(struct alps_fields *f, unsigned char *p,
 | 
				
			||||||
	f->is_mp = !!(p[0] & 0x20);
 | 
						f->is_mp = !!(p[0] & 0x20);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!f->is_mp) {
 | 
						if (!f->is_mp) {
 | 
				
			||||||
		f->x = ((p[1] & 0x7f) | ((p[4] & 0x0f) << 7));
 | 
							f->st.x = ((p[1] & 0x7f) | ((p[4] & 0x0f) << 7));
 | 
				
			||||||
		f->y = ((p[2] & 0x7f) | ((p[4] & 0xf0) << 3));
 | 
							f->st.y = ((p[2] & 0x7f) | ((p[4] & 0xf0) << 3));
 | 
				
			||||||
		f->z = (p[0] & 4) ? 0 : p[5] & 0x7f;
 | 
							f->pressure = (p[0] & 4) ? 0 : p[5] & 0x7f;
 | 
				
			||||||
		alps_decode_buttons_v3(f, p);
 | 
							alps_decode_buttons_v3(f, p);
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		f->fingers = ((p[0] & 0x6) >> 1 |
 | 
							f->fingers = ((p[0] & 0x6) >> 1 |
 | 
				
			||||||
| 
						 | 
					@ -596,19 +610,21 @@ static void alps_decode_dolphin(struct alps_fields *f, unsigned char *p,
 | 
				
			||||||
		f->x_map = (palm_data >> priv->y_bits) &
 | 
							f->x_map = (palm_data >> priv->y_bits) &
 | 
				
			||||||
			   (BIT(priv->x_bits) - 1);
 | 
								   (BIT(priv->x_bits) - 1);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse)
 | 
					static void alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct alps_data *priv = psmouse->private;
 | 
						struct alps_data *priv = psmouse->private;
 | 
				
			||||||
	unsigned char *packet = psmouse->packet;
 | 
						unsigned char *packet = psmouse->packet;
 | 
				
			||||||
	struct input_dev *dev = psmouse->dev;
 | 
					 | 
				
			||||||
	struct input_dev *dev2 = priv->dev2;
 | 
						struct input_dev *dev2 = priv->dev2;
 | 
				
			||||||
	int x1 = 0, y1 = 0, x2 = 0, y2 = 0;
 | 
						struct alps_fields *f = &priv->f;
 | 
				
			||||||
	int fingers = 0, bmap_fn;
 | 
						int fingers = 0;
 | 
				
			||||||
	struct alps_fields f = {0};
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	priv->decode_fields(&f, packet, psmouse);
 | 
						memset(f, 0, sizeof(*f));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						priv->decode_fields(f, packet, psmouse);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * There's no single feature of touchpad position and bitmap packets
 | 
						 * There's no single feature of touchpad position and bitmap packets
 | 
				
			||||||
| 
						 | 
					@ -623,22 +639,14 @@ static void alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse)
 | 
				
			||||||
		 * packet. Check for this, and when it happens process the
 | 
							 * packet. Check for this, and when it happens process the
 | 
				
			||||||
		 * position packet as usual.
 | 
							 * position packet as usual.
 | 
				
			||||||
		 */
 | 
							 */
 | 
				
			||||||
		if (f.is_mp) {
 | 
							if (f->is_mp) {
 | 
				
			||||||
			fingers = f.fingers;
 | 
								fingers = f->fingers;
 | 
				
			||||||
			if (priv->proto_version == ALPS_PROTO_V3) {
 | 
								if (priv->proto_version == ALPS_PROTO_V3) {
 | 
				
			||||||
				bmap_fn = alps_process_bitmap(priv, f.x_map,
 | 
									if (alps_process_bitmap(priv, f) == 0)
 | 
				
			||||||
							      f.y_map, &x1, &y1,
 | 
										fingers = 0; /* Use st data */
 | 
				
			||||||
							      &x2, &y2);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				/*
 | 
					 | 
				
			||||||
				 * We shouldn't report more than one finger if
 | 
					 | 
				
			||||||
				 * we don't have two coordinates.
 | 
					 | 
				
			||||||
				 */
 | 
					 | 
				
			||||||
				if (fingers > 1 && bmap_fn < 2)
 | 
					 | 
				
			||||||
					fingers = bmap_fn;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
				/* Now process position packet */
 | 
									/* Now process position packet */
 | 
				
			||||||
				priv->decode_fields(&f, priv->multi_data,
 | 
									priv->decode_fields(f, priv->multi_data,
 | 
				
			||||||
						    psmouse);
 | 
											    psmouse);
 | 
				
			||||||
			} else {
 | 
								} else {
 | 
				
			||||||
				/*
 | 
									/*
 | 
				
			||||||
| 
						 | 
					@ -647,15 +655,14 @@ static void alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse)
 | 
				
			||||||
				 * calculate Pt2, so we need to do position
 | 
									 * calculate Pt2, so we need to do position
 | 
				
			||||||
				 * packet decode first.
 | 
									 * packet decode first.
 | 
				
			||||||
				 */
 | 
									 */
 | 
				
			||||||
				priv->decode_fields(&f, priv->multi_data,
 | 
									priv->decode_fields(f, priv->multi_data,
 | 
				
			||||||
						    psmouse);
 | 
											    psmouse);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				/*
 | 
									/*
 | 
				
			||||||
				 * Since Dolphin's finger number is reliable,
 | 
									 * Since Dolphin's finger number is reliable,
 | 
				
			||||||
				 * there is no need to compare with bmap_fn.
 | 
									 * there is no need to compare with bmap_fn.
 | 
				
			||||||
				 */
 | 
									 */
 | 
				
			||||||
				alps_process_bitmap_dolphin(priv, &f, &x1, &y1,
 | 
									alps_process_bitmap_dolphin(priv, f);
 | 
				
			||||||
							    &x2, &y2);
 | 
					 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			priv->multi_packet = 0;
 | 
								priv->multi_packet = 0;
 | 
				
			||||||
| 
						 | 
					@ -670,10 +677,10 @@ static void alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse)
 | 
				
			||||||
	 * out misidentified bitmap packets, we reject anything with this
 | 
						 * out misidentified bitmap packets, we reject anything with this
 | 
				
			||||||
	 * bit set.
 | 
						 * bit set.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	if (f.is_mp)
 | 
						if (f->is_mp)
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!priv->multi_packet && f.first_mp) {
 | 
						if (!priv->multi_packet && f->first_mp) {
 | 
				
			||||||
		priv->multi_packet = 1;
 | 
							priv->multi_packet = 1;
 | 
				
			||||||
		memcpy(priv->multi_data, packet, sizeof(priv->multi_data));
 | 
							memcpy(priv->multi_data, packet, sizeof(priv->multi_data));
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
| 
						 | 
					@ -687,44 +694,15 @@ static void alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse)
 | 
				
			||||||
	 * with x, y, and z all zero, so these seem to be flukes.
 | 
						 * with x, y, and z all zero, so these seem to be flukes.
 | 
				
			||||||
	 * Ignore them.
 | 
						 * Ignore them.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	if (f.x && f.y && !f.z)
 | 
						if (f->st.x && f->st.y && !f->pressure)
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						alps_report_semi_mt_data(psmouse, fingers);
 | 
				
			||||||
	 * If we don't have MT data or the bitmaps were empty, we have
 | 
					 | 
				
			||||||
	 * to rely on ST data.
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	if (!fingers) {
 | 
					 | 
				
			||||||
		x1 = f.x;
 | 
					 | 
				
			||||||
		y1 = f.y;
 | 
					 | 
				
			||||||
		fingers = f.z > 0 ? 1 : 0;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (f.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, f.left);
 | 
					 | 
				
			||||||
	input_report_key(dev, BTN_RIGHT, f.right);
 | 
					 | 
				
			||||||
	input_report_key(dev, BTN_MIDDLE, f.middle);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (f.z > 0) {
 | 
					 | 
				
			||||||
		input_report_abs(dev, ABS_X, f.x);
 | 
					 | 
				
			||||||
		input_report_abs(dev, ABS_Y, f.y);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	input_report_abs(dev, ABS_PRESSURE, f.z);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	input_sync(dev);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!(priv->quirks & ALPS_QUIRK_TRACKSTICK_BUTTONS)) {
 | 
						if (!(priv->quirks & ALPS_QUIRK_TRACKSTICK_BUTTONS)) {
 | 
				
			||||||
		input_report_key(dev2, BTN_LEFT, f.ts_left);
 | 
							input_report_key(dev2, BTN_LEFT, f->ts_left);
 | 
				
			||||||
		input_report_key(dev2, BTN_RIGHT, f.ts_right);
 | 
							input_report_key(dev2, BTN_RIGHT, f->ts_right);
 | 
				
			||||||
		input_report_key(dev2, BTN_MIDDLE, f.ts_middle);
 | 
							input_report_key(dev2, BTN_MIDDLE, f->ts_middle);
 | 
				
			||||||
		input_sync(dev2);
 | 
							input_sync(dev2);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -823,13 +801,8 @@ static void alps_process_packet_v4(struct psmouse *psmouse)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct alps_data *priv = psmouse->private;
 | 
						struct alps_data *priv = psmouse->private;
 | 
				
			||||||
	unsigned char *packet = psmouse->packet;
 | 
						unsigned char *packet = psmouse->packet;
 | 
				
			||||||
	struct input_dev *dev = psmouse->dev;
 | 
						struct alps_fields *f = &priv->f;
 | 
				
			||||||
	int offset;
 | 
						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
 | 
						 * v4 has a 6-byte encoding for bitmap data, but this data is
 | 
				
			||||||
| 
						 | 
					@ -851,71 +824,207 @@ static void alps_process_packet_v4(struct psmouse *psmouse)
 | 
				
			||||||
	if (++priv->multi_packet > 2) {
 | 
						if (++priv->multi_packet > 2) {
 | 
				
			||||||
		priv->multi_packet = 0;
 | 
							priv->multi_packet = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		x_bitmap = ((priv->multi_data[2] & 0x1f) << 10) |
 | 
							f->x_map = ((priv->multi_data[2] & 0x1f) << 10) |
 | 
				
			||||||
			   ((priv->multi_data[3] & 0x60) << 3) |
 | 
								   ((priv->multi_data[3] & 0x60) << 3) |
 | 
				
			||||||
			   ((priv->multi_data[0] & 0x3f) << 2) |
 | 
								   ((priv->multi_data[0] & 0x3f) << 2) |
 | 
				
			||||||
			   ((priv->multi_data[1] & 0x60) >> 5);
 | 
								   ((priv->multi_data[1] & 0x60) >> 5);
 | 
				
			||||||
		y_bitmap = ((priv->multi_data[5] & 0x01) << 10) |
 | 
							f->y_map = ((priv->multi_data[5] & 0x01) << 10) |
 | 
				
			||||||
			   ((priv->multi_data[3] & 0x1f) << 5) |
 | 
								   ((priv->multi_data[3] & 0x1f) << 5) |
 | 
				
			||||||
			    (priv->multi_data[1] & 0x1f);
 | 
								    (priv->multi_data[1] & 0x1f);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		fingers = alps_process_bitmap(priv, x_bitmap, y_bitmap,
 | 
							f->fingers = alps_process_bitmap(priv, f);
 | 
				
			||||||
					      &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;
 | 
						f->left = packet[4] & 0x01;
 | 
				
			||||||
	right = packet[4] & 0x02;
 | 
						f->right = packet[4] & 0x02;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	x = ((packet[1] & 0x7f) << 4) | ((packet[3] & 0x30) >> 2) |
 | 
						f->st.x = ((packet[1] & 0x7f) << 4) | ((packet[3] & 0x30) >> 2) |
 | 
				
			||||||
		  ((packet[0] & 0x30) >> 4);
 | 
							  ((packet[0] & 0x30) >> 4);
 | 
				
			||||||
	y = ((packet[2] & 0x7f) << 4) | (packet[3] & 0x0f);
 | 
						f->st.y = ((packet[2] & 0x7f) << 4) | (packet[3] & 0x0f);
 | 
				
			||||||
	z = packet[5] & 0x7f;
 | 
						f->pressure = packet[5] & 0x7f;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						alps_report_semi_mt_data(psmouse, f->fingers);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static bool alps_is_valid_package_v7(struct psmouse *psmouse)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						switch (psmouse->pktcnt) {
 | 
				
			||||||
 | 
						case 3:
 | 
				
			||||||
 | 
							return (psmouse->packet[2] & 0x40) == 0x40;
 | 
				
			||||||
 | 
						case 4:
 | 
				
			||||||
 | 
							return (psmouse->packet[3] & 0x48) == 0x48;
 | 
				
			||||||
 | 
						case 6:
 | 
				
			||||||
 | 
							return (psmouse->packet[5] & 0x40) == 0x00;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static unsigned char alps_get_packet_id_v7(char *byte)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						unsigned char packet_id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (byte[4] & 0x40)
 | 
				
			||||||
 | 
							packet_id = V7_PACKET_ID_TWO;
 | 
				
			||||||
 | 
						else if (byte[4] & 0x01)
 | 
				
			||||||
 | 
							packet_id = V7_PACKET_ID_MULTI;
 | 
				
			||||||
 | 
						else if ((byte[0] & 0x10) && !(byte[4] & 0x43))
 | 
				
			||||||
 | 
							packet_id = V7_PACKET_ID_NEW;
 | 
				
			||||||
 | 
						else if (byte[1] == 0x00 && byte[4] == 0x00)
 | 
				
			||||||
 | 
							packet_id = V7_PACKET_ID_IDLE;
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							packet_id = V7_PACKET_ID_UNKNOWN;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return packet_id;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void alps_get_finger_coordinate_v7(struct input_mt_pos *mt,
 | 
				
			||||||
 | 
										  unsigned char *pkt,
 | 
				
			||||||
 | 
										  unsigned char pkt_id)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						mt[0].x = ((pkt[2] & 0x80) << 4);
 | 
				
			||||||
 | 
						mt[0].x |= ((pkt[2] & 0x3F) << 5);
 | 
				
			||||||
 | 
						mt[0].x |= ((pkt[3] & 0x30) >> 1);
 | 
				
			||||||
 | 
						mt[0].x |= (pkt[3] & 0x07);
 | 
				
			||||||
 | 
						mt[0].y = (pkt[1] << 3) | (pkt[0] & 0x07);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mt[1].x = ((pkt[3] & 0x80) << 4);
 | 
				
			||||||
 | 
						mt[1].x |= ((pkt[4] & 0x80) << 3);
 | 
				
			||||||
 | 
						mt[1].x |= ((pkt[4] & 0x3F) << 4);
 | 
				
			||||||
 | 
						mt[1].y = ((pkt[5] & 0x80) << 3);
 | 
				
			||||||
 | 
						mt[1].y |= ((pkt[5] & 0x3F) << 4);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch (pkt_id) {
 | 
				
			||||||
 | 
						case V7_PACKET_ID_TWO:
 | 
				
			||||||
 | 
							mt[1].x &= ~0x000F;
 | 
				
			||||||
 | 
							mt[1].y |= 0x000F;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case V7_PACKET_ID_MULTI:
 | 
				
			||||||
 | 
							mt[1].x &= ~0x003F;
 | 
				
			||||||
 | 
							mt[1].y &= ~0x0020;
 | 
				
			||||||
 | 
							mt[1].y |= ((pkt[4] & 0x02) << 4);
 | 
				
			||||||
 | 
							mt[1].y |= 0x001F;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case V7_PACKET_ID_NEW:
 | 
				
			||||||
 | 
							mt[1].x &= ~0x003F;
 | 
				
			||||||
 | 
							mt[1].x |= (pkt[0] & 0x20);
 | 
				
			||||||
 | 
							mt[1].y |= 0x000F;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mt[0].y = 0x7FF - mt[0].y;
 | 
				
			||||||
 | 
						mt[1].y = 0x7FF - mt[1].y;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int alps_get_mt_count(struct input_mt_pos *mt)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i < MAX_TOUCHES && mt[i].x != 0 && mt[i].y != 0; i++)
 | 
				
			||||||
 | 
							/* empty */;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return i;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int alps_decode_packet_v7(struct alps_fields *f,
 | 
				
			||||||
 | 
									  unsigned char *p,
 | 
				
			||||||
 | 
									  struct psmouse *psmouse)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						unsigned char pkt_id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pkt_id = alps_get_packet_id_v7(p);
 | 
				
			||||||
 | 
						if (pkt_id == V7_PACKET_ID_IDLE)
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						if (pkt_id == V7_PACKET_ID_UNKNOWN)
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						alps_get_finger_coordinate_v7(f->mt, p, pkt_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (pkt_id == V7_PACKET_ID_TWO || pkt_id == V7_PACKET_ID_MULTI) {
 | 
				
			||||||
 | 
							f->left = (p[0] & 0x80) >> 7;
 | 
				
			||||||
 | 
							f->right = (p[0] & 0x20) >> 5;
 | 
				
			||||||
 | 
							f->middle = (p[0] & 0x10) >> 4;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (pkt_id == V7_PACKET_ID_TWO)
 | 
				
			||||||
 | 
							f->fingers = alps_get_mt_count(f->mt);
 | 
				
			||||||
 | 
						else if (pkt_id == V7_PACKET_ID_MULTI)
 | 
				
			||||||
 | 
							f->fingers = 3 + (p[5] & 0x03);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void alps_process_trackstick_packet_v7(struct psmouse *psmouse)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct alps_data *priv = psmouse->private;
 | 
				
			||||||
 | 
						unsigned char *packet = psmouse->packet;
 | 
				
			||||||
 | 
						struct input_dev *dev2 = priv->dev2;
 | 
				
			||||||
 | 
						int x, y, z, left, right, middle;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * If there were no contacts in the bitmap, use ST
 | 
						 *        b7 b6 b5 b4 b3 b2 b1 b0
 | 
				
			||||||
	 * points in MT reports.
 | 
						 * Byte0   0  1  0  0  1  0  0  0
 | 
				
			||||||
	 * If there were two contacts or more, report MT data.
 | 
						 * Byte1   1  1  *  *  1  M  R  L
 | 
				
			||||||
 | 
						 * Byte2  X7  1 X5 X4 X3 X2 X1 X0
 | 
				
			||||||
 | 
						 * Byte3  Z6  1 Y6 X6  1 Y2 Y1 Y0
 | 
				
			||||||
 | 
						 * Byte4  Y7  0 Y5 Y4 Y3  1  1  0
 | 
				
			||||||
 | 
						 * Byte5 T&P  0 Z5 Z4 Z3 Z2 Z1 Z0
 | 
				
			||||||
 | 
						 * M / R / L: Middle / Right / Left button
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	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)
 | 
						x = ((packet[2] & 0xbf)) | ((packet[3] & 0x10) << 2);
 | 
				
			||||||
		input_report_key(dev, BTN_TOUCH, 1);
 | 
						y = (packet[3] & 0x07) | (packet[4] & 0xb8) |
 | 
				
			||||||
	else
 | 
						    ((packet[3] & 0x20) << 1);
 | 
				
			||||||
		input_report_key(dev, BTN_TOUCH, 0);
 | 
						z = (packet[5] & 0x3f) | ((packet[3] & 0x80) >> 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	alps_report_semi_mt_data(dev, fingers, x1, y1, x2, y2);
 | 
						left = (packet[1] & 0x01);
 | 
				
			||||||
 | 
						right = (packet[1] & 0x02) >> 1;
 | 
				
			||||||
 | 
						middle = (packet[1] & 0x04) >> 2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	input_mt_report_finger_count(dev, fingers);
 | 
						/* Divide 2 since trackpoint's speed is too fast */
 | 
				
			||||||
 | 
						input_report_rel(dev2, REL_X, (char)x / 2);
 | 
				
			||||||
 | 
						input_report_rel(dev2, REL_Y, -((char)y / 2));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	input_report_key(dev, BTN_LEFT, left);
 | 
						input_report_key(dev2, BTN_LEFT, left);
 | 
				
			||||||
	input_report_key(dev, BTN_RIGHT, right);
 | 
						input_report_key(dev2, BTN_RIGHT, right);
 | 
				
			||||||
 | 
						input_report_key(dev2, BTN_MIDDLE, middle);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (z > 0) {
 | 
						input_sync(dev2);
 | 
				
			||||||
		input_report_abs(dev, ABS_X, x);
 | 
					}
 | 
				
			||||||
		input_report_abs(dev, ABS_Y, y);
 | 
					
 | 
				
			||||||
	}
 | 
					static void alps_process_touchpad_packet_v7(struct psmouse *psmouse)
 | 
				
			||||||
	input_report_abs(dev, ABS_PRESSURE, z);
 | 
					{
 | 
				
			||||||
 | 
						struct alps_data *priv = psmouse->private;
 | 
				
			||||||
 | 
						struct input_dev *dev = psmouse->dev;
 | 
				
			||||||
 | 
						struct alps_fields *f = &priv->f;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						memset(f, 0, sizeof(*f));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (priv->decode_fields(f, psmouse->packet, psmouse))
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						alps_report_mt_data(psmouse, alps_get_mt_count(f->mt));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						input_mt_report_finger_count(dev, f->fingers);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						input_report_key(dev, BTN_LEFT, f->left);
 | 
				
			||||||
 | 
						input_report_key(dev, BTN_RIGHT, f->right);
 | 
				
			||||||
 | 
						input_report_key(dev, BTN_MIDDLE, f->middle);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	input_sync(dev);
 | 
						input_sync(dev);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void alps_process_packet_v7(struct psmouse *psmouse)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						unsigned char *packet = psmouse->packet;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (packet[0] == 0x48 && (packet[4] & 0x47) == 0x06)
 | 
				
			||||||
 | 
							alps_process_trackstick_packet_v7(psmouse);
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							alps_process_touchpad_packet_v7(psmouse);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void alps_report_bare_ps2_packet(struct psmouse *psmouse,
 | 
					static void alps_report_bare_ps2_packet(struct psmouse *psmouse,
 | 
				
			||||||
					unsigned char packet[],
 | 
										unsigned char packet[],
 | 
				
			||||||
					bool report_buttons)
 | 
										bool report_buttons)
 | 
				
			||||||
| 
						 | 
					@ -1080,6 +1189,14 @@ static psmouse_ret_t alps_process_byte(struct psmouse *psmouse)
 | 
				
			||||||
		return PSMOUSE_BAD_DATA;
 | 
							return PSMOUSE_BAD_DATA;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (priv->proto_version == ALPS_PROTO_V7 &&
 | 
				
			||||||
 | 
						    !alps_is_valid_package_v7(psmouse)) {
 | 
				
			||||||
 | 
							psmouse_dbg(psmouse, "refusing packet[%i] = %x\n",
 | 
				
			||||||
 | 
								    psmouse->pktcnt - 1,
 | 
				
			||||||
 | 
								    psmouse->packet[psmouse->pktcnt - 1]);
 | 
				
			||||||
 | 
							return PSMOUSE_BAD_DATA;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (psmouse->pktcnt == psmouse->pktsize) {
 | 
						if (psmouse->pktcnt == psmouse->pktsize) {
 | 
				
			||||||
		priv->process_packet(psmouse);
 | 
							priv->process_packet(psmouse);
 | 
				
			||||||
		return PSMOUSE_FULL_PACKET;
 | 
							return PSMOUSE_FULL_PACKET;
 | 
				
			||||||
| 
						 | 
					@ -1192,6 +1309,22 @@ static int alps_rpt_cmd(struct psmouse *psmouse, int init_command,
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static bool alps_check_valid_firmware_id(unsigned char id[])
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (id[0] == 0x73)
 | 
				
			||||||
 | 
							return true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (id[0] == 0x88 &&
 | 
				
			||||||
 | 
						    (id[1] == 0x07 ||
 | 
				
			||||||
 | 
						     id[1] == 0x08 ||
 | 
				
			||||||
 | 
						     (id[1] & 0xf0) == 0xb0 ||
 | 
				
			||||||
 | 
						     (id[1] & 0xf0) == 0xc0)) {
 | 
				
			||||||
 | 
							return true;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int alps_enter_command_mode(struct psmouse *psmouse)
 | 
					static int alps_enter_command_mode(struct psmouse *psmouse)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	unsigned char param[4];
 | 
						unsigned char param[4];
 | 
				
			||||||
| 
						 | 
					@ -1201,8 +1334,7 @@ static int alps_enter_command_mode(struct psmouse *psmouse)
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if ((param[0] != 0x88 || (param[1] != 0x07 && param[1] != 0x08)) &&
 | 
						if (!alps_check_valid_firmware_id(param)) {
 | 
				
			||||||
	    param[0] != 0x73) {
 | 
					 | 
				
			||||||
		psmouse_dbg(psmouse,
 | 
							psmouse_dbg(psmouse,
 | 
				
			||||||
			    "unknown response while entering command mode\n");
 | 
								    "unknown response while entering command mode\n");
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
| 
						 | 
					@ -1660,6 +1792,45 @@ error:
 | 
				
			||||||
	return -1;
 | 
						return -1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int alps_get_v3_v7_resolution(struct psmouse *psmouse, int reg_pitch)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int reg, x_pitch, y_pitch, x_electrode, y_electrode, x_phys, y_phys;
 | 
				
			||||||
 | 
						struct alps_data *priv = psmouse->private;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						reg = alps_command_mode_read_reg(psmouse, reg_pitch);
 | 
				
			||||||
 | 
						if (reg < 0)
 | 
				
			||||||
 | 
							return reg;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						x_pitch = (char)(reg << 4) >> 4; /* sign extend lower 4 bits */
 | 
				
			||||||
 | 
						x_pitch = 50 + 2 * x_pitch; /* In 0.1 mm units */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						y_pitch = (char)reg >> 4; /* sign extend upper 4 bits */
 | 
				
			||||||
 | 
						y_pitch = 36 + 2 * y_pitch; /* In 0.1 mm units */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						reg = alps_command_mode_read_reg(psmouse, reg_pitch + 1);
 | 
				
			||||||
 | 
						if (reg < 0)
 | 
				
			||||||
 | 
							return reg;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						x_electrode = (char)(reg << 4) >> 4; /* sign extend lower 4 bits */
 | 
				
			||||||
 | 
						x_electrode = 17 + x_electrode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						y_electrode = (char)reg >> 4; /* sign extend upper 4 bits */
 | 
				
			||||||
 | 
						y_electrode = 13 + y_electrode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						x_phys = x_pitch * (x_electrode - 1); /* In 0.1 mm units */
 | 
				
			||||||
 | 
						y_phys = y_pitch * (y_electrode - 1); /* In 0.1 mm units */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						priv->x_res = priv->x_max * 10 / x_phys; /* units / mm */
 | 
				
			||||||
 | 
						priv->y_res = priv->y_max * 10 / y_phys; /* units / mm */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						psmouse_dbg(psmouse,
 | 
				
			||||||
 | 
							    "pitch %dx%d num-electrodes %dx%d physical size %dx%d mm res %dx%d\n",
 | 
				
			||||||
 | 
							    x_pitch, y_pitch, x_electrode, y_electrode,
 | 
				
			||||||
 | 
							    x_phys / 10, y_phys / 10, priv->x_res, priv->y_res);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int alps_hw_init_rushmore_v3(struct psmouse *psmouse)
 | 
					static int alps_hw_init_rushmore_v3(struct psmouse *psmouse)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct alps_data *priv = psmouse->private;
 | 
						struct alps_data *priv = psmouse->private;
 | 
				
			||||||
| 
						 | 
					@ -1680,6 +1851,9 @@ static int alps_hw_init_rushmore_v3(struct psmouse *psmouse)
 | 
				
			||||||
	    alps_command_mode_write_reg(psmouse, 0xc2cb, 0x00))
 | 
						    alps_command_mode_write_reg(psmouse, 0xc2cb, 0x00))
 | 
				
			||||||
		goto error;
 | 
							goto error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (alps_get_v3_v7_resolution(psmouse, 0xc2da))
 | 
				
			||||||
 | 
							goto error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	reg_val = alps_command_mode_read_reg(psmouse, 0xc2c6);
 | 
						reg_val = alps_command_mode_read_reg(psmouse, 0xc2c6);
 | 
				
			||||||
	if (reg_val == -1)
 | 
						if (reg_val == -1)
 | 
				
			||||||
		goto error;
 | 
							goto error;
 | 
				
			||||||
| 
						 | 
					@ -1856,6 +2030,35 @@ static int alps_hw_init_dolphin_v1(struct psmouse *psmouse)
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int alps_hw_init_v7(struct psmouse *psmouse)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct ps2dev *ps2dev = &psmouse->ps2dev;
 | 
				
			||||||
 | 
						int reg_val, ret = -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (alps_enter_command_mode(psmouse) ||
 | 
				
			||||||
 | 
						    alps_command_mode_read_reg(psmouse, 0xc2d9) == -1)
 | 
				
			||||||
 | 
							goto error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (alps_get_v3_v7_resolution(psmouse, 0xc397))
 | 
				
			||||||
 | 
							goto error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (alps_command_mode_write_reg(psmouse, 0xc2c9, 0x64))
 | 
				
			||||||
 | 
							goto error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						reg_val = alps_command_mode_read_reg(psmouse, 0xc2c4);
 | 
				
			||||||
 | 
						if (reg_val == -1)
 | 
				
			||||||
 | 
							goto error;
 | 
				
			||||||
 | 
						if (__alps_command_mode_write_reg(psmouse, reg_val | 0x02))
 | 
				
			||||||
 | 
							goto error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						alps_exit_command_mode(psmouse);
 | 
				
			||||||
 | 
						return ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					error:
 | 
				
			||||||
 | 
						alps_exit_command_mode(psmouse);
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void alps_set_defaults(struct alps_data *priv)
 | 
					static void alps_set_defaults(struct alps_data *priv)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	priv->byte0 = 0x8f;
 | 
						priv->byte0 = 0x8f;
 | 
				
			||||||
| 
						 | 
					@ -1914,6 +2117,21 @@ static void alps_set_defaults(struct alps_data *priv)
 | 
				
			||||||
		priv->x_max = 2047;
 | 
							priv->x_max = 2047;
 | 
				
			||||||
		priv->y_max = 1535;
 | 
							priv->y_max = 1535;
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
 | 
						case ALPS_PROTO_V7:
 | 
				
			||||||
 | 
							priv->hw_init = alps_hw_init_v7;
 | 
				
			||||||
 | 
							priv->process_packet = alps_process_packet_v7;
 | 
				
			||||||
 | 
							priv->decode_fields = alps_decode_packet_v7;
 | 
				
			||||||
 | 
							priv->set_abs_params = alps_set_abs_params_mt;
 | 
				
			||||||
 | 
							priv->nibble_commands = alps_v3_nibble_commands;
 | 
				
			||||||
 | 
							priv->addr_command = PSMOUSE_CMD_RESET_WRAP;
 | 
				
			||||||
 | 
							priv->x_max = 0xfff;
 | 
				
			||||||
 | 
							priv->y_max = 0x7ff;
 | 
				
			||||||
 | 
							priv->byte0 = 0x48;
 | 
				
			||||||
 | 
							priv->mask0 = 0x48;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (priv->fw_ver[1] != 0xba)
 | 
				
			||||||
 | 
								priv->flags |= ALPS_BUTTONPAD;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1972,6 +2190,9 @@ static int alps_identify(struct psmouse *psmouse, struct alps_data *priv)
 | 
				
			||||||
	    alps_exit_command_mode(psmouse))
 | 
						    alps_exit_command_mode(psmouse))
 | 
				
			||||||
		return -EIO;
 | 
							return -EIO;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Save the Firmware version */
 | 
				
			||||||
 | 
						memcpy(priv->fw_ver, ec, 3);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (alps_match_table(psmouse, priv, e7, ec) == 0) {
 | 
						if (alps_match_table(psmouse, priv, e7, ec) == 0) {
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
	} else if (e7[0] == 0x73 && e7[1] == 0x03 && e7[2] == 0x50 &&
 | 
						} else if (e7[0] == 0x73 && e7[1] == 0x03 && e7[2] == 0x50 &&
 | 
				
			||||||
| 
						 | 
					@ -1981,6 +2202,12 @@ static int alps_identify(struct psmouse *psmouse, struct alps_data *priv)
 | 
				
			||||||
		if (alps_dolphin_get_device_area(psmouse, priv))
 | 
							if (alps_dolphin_get_device_area(psmouse, priv))
 | 
				
			||||||
			return -EIO;
 | 
								return -EIO;
 | 
				
			||||||
		else
 | 
							else
 | 
				
			||||||
 | 
								return 0;
 | 
				
			||||||
 | 
						} else if (ec[0] == 0x88 &&
 | 
				
			||||||
 | 
							   ((ec[1] & 0xf0) == 0xb0 || (ec[1] & 0xf0) == 0xc0)) {
 | 
				
			||||||
 | 
							priv->proto_version = ALPS_PROTO_V7;
 | 
				
			||||||
 | 
							alps_set_defaults(priv);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
	} else if (ec[0] == 0x88 && ec[1] == 0x08) {
 | 
						} else if (ec[0] == 0x88 && ec[1] == 0x08) {
 | 
				
			||||||
		priv->proto_version = ALPS_PROTO_V3;
 | 
							priv->proto_version = ALPS_PROTO_V3;
 | 
				
			||||||
| 
						 | 
					@ -1990,6 +2217,7 @@ static int alps_identify(struct psmouse *psmouse, struct alps_data *priv)
 | 
				
			||||||
		priv->decode_fields = alps_decode_rushmore;
 | 
							priv->decode_fields = alps_decode_rushmore;
 | 
				
			||||||
		priv->x_bits = 16;
 | 
							priv->x_bits = 16;
 | 
				
			||||||
		priv->y_bits = 12;
 | 
							priv->y_bits = 12;
 | 
				
			||||||
 | 
							priv->flags |= ALPS_IS_RUSHMORE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* hack to make addr_command, nibble_command available */
 | 
							/* hack to make addr_command, nibble_command available */
 | 
				
			||||||
		psmouse->private = priv;
 | 
							psmouse->private = priv;
 | 
				
			||||||
| 
						 | 
					@ -2044,17 +2272,21 @@ static void alps_set_abs_params_st(struct alps_data *priv,
 | 
				
			||||||
static void alps_set_abs_params_mt(struct alps_data *priv,
 | 
					static void alps_set_abs_params_mt(struct alps_data *priv,
 | 
				
			||||||
				   struct input_dev *dev1)
 | 
									   struct input_dev *dev1)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	set_bit(INPUT_PROP_SEMI_MT, dev1->propbit);
 | 
					 | 
				
			||||||
	input_mt_init_slots(dev1, 2, 0);
 | 
					 | 
				
			||||||
	input_set_abs_params(dev1, ABS_MT_POSITION_X, 0, priv->x_max, 0, 0);
 | 
						input_set_abs_params(dev1, ABS_MT_POSITION_X, 0, priv->x_max, 0, 0);
 | 
				
			||||||
	input_set_abs_params(dev1, ABS_MT_POSITION_Y, 0, priv->y_max, 0, 0);
 | 
						input_set_abs_params(dev1, ABS_MT_POSITION_Y, 0, priv->y_max, 0, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	set_bit(BTN_TOOL_DOUBLETAP, dev1->keybit);
 | 
						input_abs_set_res(dev1, ABS_MT_POSITION_X, priv->x_res);
 | 
				
			||||||
 | 
						input_abs_set_res(dev1, ABS_MT_POSITION_Y, priv->y_res);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						input_mt_init_slots(dev1, MAX_TOUCHES, INPUT_MT_POINTER |
 | 
				
			||||||
 | 
							INPUT_MT_DROP_UNUSED | INPUT_MT_TRACK | INPUT_MT_SEMI_MT);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	set_bit(BTN_TOOL_TRIPLETAP, dev1->keybit);
 | 
						set_bit(BTN_TOOL_TRIPLETAP, dev1->keybit);
 | 
				
			||||||
	set_bit(BTN_TOOL_QUADTAP, dev1->keybit);
 | 
						set_bit(BTN_TOOL_QUADTAP, dev1->keybit);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	input_set_abs_params(dev1, ABS_X, 0, priv->x_max, 0, 0);
 | 
						/* V7 is real multi-touch */
 | 
				
			||||||
	input_set_abs_params(dev1, ABS_Y, 0, priv->y_max, 0, 0);
 | 
						if (priv->proto_version == ALPS_PROTO_V7)
 | 
				
			||||||
 | 
							clear_bit(INPUT_PROP_SEMI_MT, dev1->propbit);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int alps_init(struct psmouse *psmouse)
 | 
					int alps_init(struct psmouse *psmouse)
 | 
				
			||||||
| 
						 | 
					@ -2100,6 +2332,8 @@ int alps_init(struct psmouse *psmouse)
 | 
				
			||||||
	dev1->evbit[BIT_WORD(EV_ABS)] |= BIT_MASK(EV_ABS);
 | 
						dev1->evbit[BIT_WORD(EV_ABS)] |= BIT_MASK(EV_ABS);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	priv->set_abs_params(priv, dev1);
 | 
						priv->set_abs_params(priv, dev1);
 | 
				
			||||||
 | 
						/* No pressure on V7 */
 | 
				
			||||||
 | 
						if (priv->proto_version != ALPS_PROTO_V7)
 | 
				
			||||||
		input_set_abs_params(dev1, ABS_PRESSURE, 0, 127, 0, 0);
 | 
							input_set_abs_params(dev1, ABS_PRESSURE, 0, 127, 0, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (priv->flags & ALPS_WHEEL) {
 | 
						if (priv->flags & ALPS_WHEEL) {
 | 
				
			||||||
| 
						 | 
					@ -2117,6 +2351,9 @@ int alps_init(struct psmouse *psmouse)
 | 
				
			||||||
		dev1->keybit[BIT_WORD(BTN_1)] |= BIT_MASK(BTN_1);
 | 
							dev1->keybit[BIT_WORD(BTN_1)] |= BIT_MASK(BTN_1);
 | 
				
			||||||
		dev1->keybit[BIT_WORD(BTN_2)] |= BIT_MASK(BTN_2);
 | 
							dev1->keybit[BIT_WORD(BTN_2)] |= BIT_MASK(BTN_2);
 | 
				
			||||||
		dev1->keybit[BIT_WORD(BTN_3)] |= BIT_MASK(BTN_3);
 | 
							dev1->keybit[BIT_WORD(BTN_3)] |= BIT_MASK(BTN_3);
 | 
				
			||||||
 | 
						} else if (priv->flags & ALPS_BUTTONPAD) {
 | 
				
			||||||
 | 
							set_bit(INPUT_PROP_BUTTONPAD, dev1->propbit);
 | 
				
			||||||
 | 
							clear_bit(BTN_RIGHT, dev1->keybit);
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		dev1->keybit[BIT_WORD(BTN_MIDDLE)] |= BIT_MASK(BTN_MIDDLE);
 | 
							dev1->keybit[BIT_WORD(BTN_MIDDLE)] |= BIT_MASK(BTN_MIDDLE);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -12,17 +12,39 @@
 | 
				
			||||||
#ifndef _ALPS_H
 | 
					#ifndef _ALPS_H
 | 
				
			||||||
#define _ALPS_H
 | 
					#define _ALPS_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <linux/input/mt.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define ALPS_PROTO_V1	1
 | 
					#define ALPS_PROTO_V1	1
 | 
				
			||||||
#define ALPS_PROTO_V2	2
 | 
					#define ALPS_PROTO_V2	2
 | 
				
			||||||
#define ALPS_PROTO_V3	3
 | 
					#define ALPS_PROTO_V3	3
 | 
				
			||||||
#define ALPS_PROTO_V4	4
 | 
					#define ALPS_PROTO_V4	4
 | 
				
			||||||
#define ALPS_PROTO_V5	5
 | 
					#define ALPS_PROTO_V5	5
 | 
				
			||||||
#define ALPS_PROTO_V6	6
 | 
					#define ALPS_PROTO_V6	6
 | 
				
			||||||
 | 
					#define ALPS_PROTO_V7	7	/* t3btl t4s */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define MAX_TOUCHES	2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define DOLPHIN_COUNT_PER_ELECTRODE	64
 | 
					#define DOLPHIN_COUNT_PER_ELECTRODE	64
 | 
				
			||||||
#define DOLPHIN_PROFILE_XOFFSET		8	/* x-electrode offset */
 | 
					#define DOLPHIN_PROFILE_XOFFSET		8	/* x-electrode offset */
 | 
				
			||||||
#define DOLPHIN_PROFILE_YOFFSET		1	/* y-electrode offset */
 | 
					#define DOLPHIN_PROFILE_YOFFSET		1	/* y-electrode offset */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * enum V7_PACKET_ID - defines the packet type for V7
 | 
				
			||||||
 | 
					 * V7_PACKET_ID_IDLE: There's no finger and no button activity.
 | 
				
			||||||
 | 
					 * V7_PACKET_ID_TWO: There's one or two non-resting fingers on touchpad
 | 
				
			||||||
 | 
					 *  or there's button activities.
 | 
				
			||||||
 | 
					 * V7_PACKET_ID_MULTI: There are at least three non-resting fingers.
 | 
				
			||||||
 | 
					 * V7_PACKET_ID_NEW: The finger position in slot is not continues from
 | 
				
			||||||
 | 
					 *  previous packet.
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					enum V7_PACKET_ID {
 | 
				
			||||||
 | 
						 V7_PACKET_ID_IDLE,
 | 
				
			||||||
 | 
						 V7_PACKET_ID_TWO,
 | 
				
			||||||
 | 
						 V7_PACKET_ID_MULTI,
 | 
				
			||||||
 | 
						 V7_PACKET_ID_NEW,
 | 
				
			||||||
 | 
						 V7_PACKET_ID_UNKNOWN,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * struct alps_model_info - touchpad ID table
 | 
					 * struct alps_model_info - touchpad ID table
 | 
				
			||||||
 * @signature: E7 response string to match.
 | 
					 * @signature: E7 response string to match.
 | 
				
			||||||
| 
						 | 
					@ -46,7 +68,7 @@ struct alps_model_info {
 | 
				
			||||||
	unsigned char command_mode_resp;
 | 
						unsigned char command_mode_resp;
 | 
				
			||||||
	unsigned char proto_version;
 | 
						unsigned char proto_version;
 | 
				
			||||||
	unsigned char byte0, mask0;
 | 
						unsigned char byte0, mask0;
 | 
				
			||||||
	unsigned char flags;
 | 
						int flags;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
| 
						 | 
					@ -65,14 +87,19 @@ struct alps_nibble_commands {
 | 
				
			||||||
	unsigned char data;
 | 
						unsigned char data;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct alps_bitmap_point {
 | 
				
			||||||
 | 
						int start_bit;
 | 
				
			||||||
 | 
						int num_bits;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * struct alps_fields - decoded version of the report packet
 | 
					 * struct alps_fields - decoded version of the report packet
 | 
				
			||||||
 * @x_map: Bitmap of active X positions for MT.
 | 
					 * @x_map: Bitmap of active X positions for MT.
 | 
				
			||||||
 * @y_map: Bitmap of active Y positions for MT.
 | 
					 * @y_map: Bitmap of active Y positions for MT.
 | 
				
			||||||
 * @fingers: Number of fingers for MT.
 | 
					 * @fingers: Number of fingers for MT.
 | 
				
			||||||
 * @x: X position for ST.
 | 
					 * @pressure: Pressure.
 | 
				
			||||||
 * @y: Y position for ST.
 | 
					 * @st: position for ST.
 | 
				
			||||||
 * @z: Z position for ST.
 | 
					 * @mt: position for MT.
 | 
				
			||||||
 * @first_mp: Packet is the first of a multi-packet report.
 | 
					 * @first_mp: Packet is the first of a multi-packet report.
 | 
				
			||||||
 * @is_mp: Packet is part of a multi-packet report.
 | 
					 * @is_mp: Packet is part of a multi-packet report.
 | 
				
			||||||
 * @left: Left touchpad button is active.
 | 
					 * @left: Left touchpad button is active.
 | 
				
			||||||
| 
						 | 
					@ -86,9 +113,11 @@ struct alps_fields {
 | 
				
			||||||
	unsigned int x_map;
 | 
						unsigned int x_map;
 | 
				
			||||||
	unsigned int y_map;
 | 
						unsigned int y_map;
 | 
				
			||||||
	unsigned int fingers;
 | 
						unsigned int fingers;
 | 
				
			||||||
	unsigned int x;
 | 
					
 | 
				
			||||||
	unsigned int y;
 | 
						int pressure;
 | 
				
			||||||
	unsigned int z;
 | 
						struct input_mt_pos st;
 | 
				
			||||||
 | 
						struct input_mt_pos mt[MAX_TOUCHES];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	unsigned int first_mp:1;
 | 
						unsigned int first_mp:1;
 | 
				
			||||||
	unsigned int is_mp:1;
 | 
						unsigned int is_mp:1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -113,6 +142,7 @@ struct alps_fields {
 | 
				
			||||||
 *   known format for this model.  The first byte of the report, ANDed with
 | 
					 *   known format for this model.  The first byte of the report, ANDed with
 | 
				
			||||||
 *   mask0, should match byte0.
 | 
					 *   mask0, should match byte0.
 | 
				
			||||||
 * @mask0: The mask used to check the first byte of the report.
 | 
					 * @mask0: The mask used to check the first byte of the report.
 | 
				
			||||||
 | 
					 * @fw_ver: cached copy of firmware version (EC report)
 | 
				
			||||||
 * @flags: Additional device capabilities (passthrough port, trackstick, etc.).
 | 
					 * @flags: Additional device capabilities (passthrough port, trackstick, etc.).
 | 
				
			||||||
 * @x_max: Largest possible X position value.
 | 
					 * @x_max: Largest possible X position value.
 | 
				
			||||||
 * @y_max: Largest possible Y position value.
 | 
					 * @y_max: Largest possible Y position value.
 | 
				
			||||||
| 
						 | 
					@ -125,11 +155,7 @@ struct alps_fields {
 | 
				
			||||||
 * @prev_fin: Finger bit from previous packet.
 | 
					 * @prev_fin: Finger bit from previous packet.
 | 
				
			||||||
 * @multi_packet: Multi-packet data in progress.
 | 
					 * @multi_packet: Multi-packet data in progress.
 | 
				
			||||||
 * @multi_data: Saved multi-packet data.
 | 
					 * @multi_data: Saved multi-packet data.
 | 
				
			||||||
 * @x1: First X coordinate from last MT report.
 | 
					 * @f: Decoded packet data fields.
 | 
				
			||||||
 * @x2: Second X coordinate from last MT report.
 | 
					 | 
				
			||||||
 * @y1: First Y coordinate from last MT report.
 | 
					 | 
				
			||||||
 * @y2: Second Y coordinate from last MT report.
 | 
					 | 
				
			||||||
 * @fingers: Number of fingers from last MT report.
 | 
					 | 
				
			||||||
 * @quirks: Bitmap of ALPS_QUIRK_*.
 | 
					 * @quirks: Bitmap of ALPS_QUIRK_*.
 | 
				
			||||||
 * @timer: Timer for flushing out the final report packet in the stream.
 | 
					 * @timer: Timer for flushing out the final report packet in the stream.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
| 
						 | 
					@ -142,23 +168,25 @@ struct alps_data {
 | 
				
			||||||
	int addr_command;
 | 
						int addr_command;
 | 
				
			||||||
	unsigned char proto_version;
 | 
						unsigned char proto_version;
 | 
				
			||||||
	unsigned char byte0, mask0;
 | 
						unsigned char byte0, mask0;
 | 
				
			||||||
	unsigned char flags;
 | 
						unsigned char fw_ver[3];
 | 
				
			||||||
 | 
						int flags;
 | 
				
			||||||
	int x_max;
 | 
						int x_max;
 | 
				
			||||||
	int y_max;
 | 
						int y_max;
 | 
				
			||||||
	int x_bits;
 | 
						int x_bits;
 | 
				
			||||||
	int y_bits;
 | 
						int y_bits;
 | 
				
			||||||
 | 
						unsigned int x_res;
 | 
				
			||||||
 | 
						unsigned int y_res;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int (*hw_init)(struct psmouse *psmouse);
 | 
						int (*hw_init)(struct psmouse *psmouse);
 | 
				
			||||||
	void (*process_packet)(struct psmouse *psmouse);
 | 
						void (*process_packet)(struct psmouse *psmouse);
 | 
				
			||||||
	void (*decode_fields)(struct alps_fields *f, unsigned char *p,
 | 
						int (*decode_fields)(struct alps_fields *f, unsigned char *p,
 | 
				
			||||||
			      struct psmouse *psmouse);
 | 
								      struct psmouse *psmouse);
 | 
				
			||||||
	void (*set_abs_params)(struct alps_data *priv, struct input_dev *dev1);
 | 
						void (*set_abs_params)(struct alps_data *priv, struct input_dev *dev1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int prev_fin;
 | 
						int prev_fin;
 | 
				
			||||||
	int multi_packet;
 | 
						int multi_packet;
 | 
				
			||||||
	unsigned char multi_data[6];
 | 
						unsigned char multi_data[6];
 | 
				
			||||||
	int x1, x2, y1, y2;
 | 
						struct alps_fields f;
 | 
				
			||||||
	int fingers;
 | 
					 | 
				
			||||||
	u8 quirks;
 | 
						u8 quirks;
 | 
				
			||||||
	struct timer_list timer;
 | 
						struct timer_list timer;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -170,6 +170,15 @@ static void hv_kbd_on_receive(struct hv_device *hv_dev,
 | 
				
			||||||
			serio_interrupt(kbd_dev->hv_serio, scan_code, 0);
 | 
								serio_interrupt(kbd_dev->hv_serio, scan_code, 0);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		spin_unlock_irqrestore(&kbd_dev->lock, flags);
 | 
							spin_unlock_irqrestore(&kbd_dev->lock, flags);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/*
 | 
				
			||||||
 | 
							 * Only trigger a wakeup on key down, otherwise
 | 
				
			||||||
 | 
							 * "echo freeze > /sys/power/state" can't really enter the
 | 
				
			||||||
 | 
							 * state because the Enter-UP can trigger a wakeup at once.
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							if (!(info & IS_BREAK))
 | 
				
			||||||
 | 
								pm_wakeup_event(&hv_dev->device, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
| 
						 | 
					@ -376,6 +385,9 @@ static int hv_kbd_probe(struct hv_device *hv_dev,
 | 
				
			||||||
		goto err_close_vmbus;
 | 
							goto err_close_vmbus;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	serio_register_port(kbd_dev->hv_serio);
 | 
						serio_register_port(kbd_dev->hv_serio);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						device_init_wakeup(&hv_dev->device, true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
err_close_vmbus:
 | 
					err_close_vmbus:
 | 
				
			||||||
| 
						 | 
					@ -390,6 +402,7 @@ static int hv_kbd_remove(struct hv_device *hv_dev)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct hv_kbd_dev *kbd_dev = hv_get_drvdata(hv_dev);
 | 
						struct hv_kbd_dev *kbd_dev = hv_get_drvdata(hv_dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						device_init_wakeup(&hv_dev->device, false);
 | 
				
			||||||
	serio_unregister_port(kbd_dev->hv_serio);
 | 
						serio_unregister_port(kbd_dev->hv_serio);
 | 
				
			||||||
	vmbus_close(hv_dev->channel);
 | 
						vmbus_close(hv_dev->channel);
 | 
				
			||||||
	kfree(kbd_dev);
 | 
						kfree(kbd_dev);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -73,20 +73,14 @@ config TABLET_USB_KBTAB
 | 
				
			||||||
	  To compile this driver as a module, choose M here: the
 | 
						  To compile this driver as a module, choose M here: the
 | 
				
			||||||
	  module will be called kbtab.
 | 
						  module will be called kbtab.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
config TABLET_USB_WACOM
 | 
					config TABLET_SERIAL_WACOM4
 | 
				
			||||||
	tristate "Wacom Intuos/Graphire tablet support (USB)"
 | 
						tristate "Wacom protocol 4 serial tablet support"
 | 
				
			||||||
	depends on USB_ARCH_HAS_HCD
 | 
						select SERIO
 | 
				
			||||||
	select POWER_SUPPLY
 | 
					 | 
				
			||||||
	select USB
 | 
					 | 
				
			||||||
	select NEW_LEDS
 | 
					 | 
				
			||||||
	select LEDS_CLASS
 | 
					 | 
				
			||||||
	help
 | 
						help
 | 
				
			||||||
	  Say Y here if you want to use the USB version of the Wacom Intuos
 | 
						  Say Y here if you want to use Wacom protocol 4 serial tablets.
 | 
				
			||||||
	  or Graphire tablet.  Make sure to say Y to "Mouse support"
 | 
						  E.g. serial versions of the Cintiq, Graphire or Penpartner.
 | 
				
			||||||
	  (CONFIG_INPUT_MOUSEDEV) and/or "Event interface support"
 | 
					 | 
				
			||||||
	  (CONFIG_INPUT_EVDEV) as well.
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	  To compile this driver as a module, choose M here: the
 | 
						  To compile this driver as a module, choose M here: the
 | 
				
			||||||
	  module will be called wacom.
 | 
						  module will be called wacom_serial4.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
endif
 | 
					endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,12 +2,10 @@
 | 
				
			||||||
# Makefile for the tablet drivers
 | 
					# Makefile for the tablet drivers
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Multipart objects.
 | 
					 | 
				
			||||||
wacom-objs	:= wacom_wac.o wacom_sys.o
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
obj-$(CONFIG_TABLET_USB_ACECAD)	+= acecad.o
 | 
					obj-$(CONFIG_TABLET_USB_ACECAD)	+= acecad.o
 | 
				
			||||||
obj-$(CONFIG_TABLET_USB_AIPTEK)	+= aiptek.o
 | 
					obj-$(CONFIG_TABLET_USB_AIPTEK)	+= aiptek.o
 | 
				
			||||||
obj-$(CONFIG_TABLET_USB_GTCO)	+= gtco.o
 | 
					obj-$(CONFIG_TABLET_USB_GTCO)	+= gtco.o
 | 
				
			||||||
obj-$(CONFIG_TABLET_USB_HANWANG) += hanwang.o
 | 
					obj-$(CONFIG_TABLET_USB_HANWANG) += hanwang.o
 | 
				
			||||||
obj-$(CONFIG_TABLET_USB_KBTAB)	+= kbtab.o
 | 
					obj-$(CONFIG_TABLET_USB_KBTAB)	+= kbtab.o
 | 
				
			||||||
obj-$(CONFIG_TABLET_USB_WACOM)	+= wacom.o
 | 
					obj-$(CONFIG_TABLET_SERIAL_WACOM4) += wacom_serial4.o
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										620
									
								
								drivers/input/tablet/wacom_serial4.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										620
									
								
								drivers/input/tablet/wacom_serial4.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,620 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Wacom protocol 4 serial tablet driver
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Copyright 2014      Hans de Goede <hdegoede@redhat.com>
 | 
				
			||||||
 | 
					 * Copyright 2011-2012 Julian Squires <julian@cipht.net>
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * 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. See the file COPYING in the main directory of
 | 
				
			||||||
 | 
					 * this archive for more details.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Many thanks to Bill Seremetis, without whom PenPartner support
 | 
				
			||||||
 | 
					 * would not have been possible. Thanks to Patrick Mahoney.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This driver was developed with reference to much code written by others,
 | 
				
			||||||
 | 
					 * particularly:
 | 
				
			||||||
 | 
					 *  - elo, gunze drivers by Vojtech Pavlik <vojtech@ucw.cz>;
 | 
				
			||||||
 | 
					 *  - wacom_w8001 driver by Jaya Kumar <jayakumar.lkml@gmail.com>;
 | 
				
			||||||
 | 
					 *  - the USB wacom input driver, credited to many people
 | 
				
			||||||
 | 
					 *    (see drivers/input/tablet/wacom.h);
 | 
				
			||||||
 | 
					 *  - new and old versions of linuxwacom / xf86-input-wacom credited to
 | 
				
			||||||
 | 
					 *    Frederic Lepied, France. <Lepied@XFree86.org> and
 | 
				
			||||||
 | 
					 *    Ping Cheng, Wacom. <pingc@wacom.com>;
 | 
				
			||||||
 | 
					 *  - and xf86wacom.c (a presumably ancient version of the linuxwacom code),
 | 
				
			||||||
 | 
					 *    by Frederic Lepied and Raph Levien <raph@gtk.org>.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * To do:
 | 
				
			||||||
 | 
					 *  - support pad buttons; (requires access to a model with pad buttons)
 | 
				
			||||||
 | 
					 *  - support (protocol 4-style) tilt (requires access to a > 1.4 rom model)
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Wacom serial protocol 4 documentation taken from linuxwacom-0.9.9 code,
 | 
				
			||||||
 | 
					 * protocol 4 uses 7 or 9 byte of data in the following format:
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *	Byte 1
 | 
				
			||||||
 | 
					 *	bit 7  Sync bit always 1
 | 
				
			||||||
 | 
					 *	bit 6  Pointing device detected
 | 
				
			||||||
 | 
					 *	bit 5  Cursor = 0 / Stylus = 1
 | 
				
			||||||
 | 
					 *	bit 4  Reserved
 | 
				
			||||||
 | 
					 *	bit 3  1 if a button on the pointing device has been pressed
 | 
				
			||||||
 | 
					 *	bit 2  P0 (optional)
 | 
				
			||||||
 | 
					 *	bit 1  X15
 | 
				
			||||||
 | 
					 *	bit 0  X14
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *	Byte 2
 | 
				
			||||||
 | 
					 *	bit 7  Always 0
 | 
				
			||||||
 | 
					 *	bits 6-0 = X13 - X7
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *	Byte 3
 | 
				
			||||||
 | 
					 *	bit 7  Always 0
 | 
				
			||||||
 | 
					 *	bits 6-0 = X6 - X0
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *	Byte 4
 | 
				
			||||||
 | 
					 *	bit 7  Always 0
 | 
				
			||||||
 | 
					 *	bit 6  B3
 | 
				
			||||||
 | 
					 *	bit 5  B2
 | 
				
			||||||
 | 
					 *	bit 4  B1
 | 
				
			||||||
 | 
					 *	bit 3  B0
 | 
				
			||||||
 | 
					 *	bit 2  P1 (optional)
 | 
				
			||||||
 | 
					 *	bit 1  Y15
 | 
				
			||||||
 | 
					 *	bit 0  Y14
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *	Byte 5
 | 
				
			||||||
 | 
					 *	bit 7  Always 0
 | 
				
			||||||
 | 
					 *	bits 6-0 = Y13 - Y7
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *	Byte 6
 | 
				
			||||||
 | 
					 *	bit 7  Always 0
 | 
				
			||||||
 | 
					 *	bits 6-0 = Y6 - Y0
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *	Byte 7
 | 
				
			||||||
 | 
					 *	bit 7 Always 0
 | 
				
			||||||
 | 
					 *	bit 6  Sign of pressure data; or wheel-rel for cursor tool
 | 
				
			||||||
 | 
					 *	bit 5  P7; or REL1 for cursor tool
 | 
				
			||||||
 | 
					 *	bit 4  P6; or REL0 for cursor tool
 | 
				
			||||||
 | 
					 *	bit 3  P5
 | 
				
			||||||
 | 
					 *	bit 2  P4
 | 
				
			||||||
 | 
					 *	bit 1  P3
 | 
				
			||||||
 | 
					 *	bit 0  P2
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *	byte 8 and 9 are optional and present only
 | 
				
			||||||
 | 
					 *	in tilt mode.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *	Byte 8
 | 
				
			||||||
 | 
					 *	bit 7 Always 0
 | 
				
			||||||
 | 
					 *	bit 6 Sign of tilt X
 | 
				
			||||||
 | 
					 *	bit 5  Xt6
 | 
				
			||||||
 | 
					 *	bit 4  Xt5
 | 
				
			||||||
 | 
					 *	bit 3  Xt4
 | 
				
			||||||
 | 
					 *	bit 2  Xt3
 | 
				
			||||||
 | 
					 *	bit 1  Xt2
 | 
				
			||||||
 | 
					 *	bit 0  Xt1
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *	Byte 9
 | 
				
			||||||
 | 
					 *	bit 7 Always 0
 | 
				
			||||||
 | 
					 *	bit 6 Sign of tilt Y
 | 
				
			||||||
 | 
					 *	bit 5  Yt6
 | 
				
			||||||
 | 
					 *	bit 4  Yt5
 | 
				
			||||||
 | 
					 *	bit 3  Yt4
 | 
				
			||||||
 | 
					 *	bit 2  Yt3
 | 
				
			||||||
 | 
					 *	bit 1  Yt2
 | 
				
			||||||
 | 
					 *	bit 0  Yt1
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <linux/completion.h>
 | 
				
			||||||
 | 
					#include <linux/init.h>
 | 
				
			||||||
 | 
					#include <linux/input.h>
 | 
				
			||||||
 | 
					#include <linux/interrupt.h>
 | 
				
			||||||
 | 
					#include <linux/kernel.h>
 | 
				
			||||||
 | 
					#include <linux/module.h>
 | 
				
			||||||
 | 
					#include <linux/serio.h>
 | 
				
			||||||
 | 
					#include <linux/slab.h>
 | 
				
			||||||
 | 
					#include <linux/string.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					MODULE_AUTHOR("Julian Squires <julian@cipht.net>, Hans de Goede <hdegoede@redhat.com>");
 | 
				
			||||||
 | 
					MODULE_DESCRIPTION("Wacom protocol 4 serial tablet driver");
 | 
				
			||||||
 | 
					MODULE_LICENSE("GPL");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define REQUEST_MODEL_AND_ROM_VERSION	"~#"
 | 
				
			||||||
 | 
					#define REQUEST_MAX_COORDINATES		"~C\r"
 | 
				
			||||||
 | 
					#define REQUEST_CONFIGURATION_STRING	"~R\r"
 | 
				
			||||||
 | 
					#define REQUEST_RESET_TO_PROTOCOL_IV	"\r#"
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Note: sending "\r$\r" causes at least the Digitizer II to send
 | 
				
			||||||
 | 
					 * packets in ASCII instead of binary.  "\r#" seems to undo that.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define COMMAND_START_SENDING_PACKETS		"ST\r"
 | 
				
			||||||
 | 
					#define COMMAND_STOP_SENDING_PACKETS		"SP\r"
 | 
				
			||||||
 | 
					#define COMMAND_MULTI_MODE_INPUT		"MU1\r"
 | 
				
			||||||
 | 
					#define COMMAND_ORIGIN_IN_UPPER_LEFT		"OC1\r"
 | 
				
			||||||
 | 
					#define COMMAND_ENABLE_ALL_MACRO_BUTTONS	"~M0\r"
 | 
				
			||||||
 | 
					#define COMMAND_DISABLE_GROUP_1_MACRO_BUTTONS	"~M1\r"
 | 
				
			||||||
 | 
					#define COMMAND_TRANSMIT_AT_MAX_RATE		"IT0\r"
 | 
				
			||||||
 | 
					#define COMMAND_DISABLE_INCREMENTAL_MODE	"IN0\r"
 | 
				
			||||||
 | 
					#define COMMAND_ENABLE_CONTINUOUS_MODE		"SR\r"
 | 
				
			||||||
 | 
					#define COMMAND_ENABLE_PRESSURE_MODE		"PH1\r"
 | 
				
			||||||
 | 
					#define COMMAND_Z_FILTER			"ZF1\r"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Note that this is a protocol 4 packet without tilt information. */
 | 
				
			||||||
 | 
					#define PACKET_LENGTH		7
 | 
				
			||||||
 | 
					#define DATA_SIZE		32
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* flags */
 | 
				
			||||||
 | 
					#define F_COVERS_SCREEN		0x01
 | 
				
			||||||
 | 
					#define F_HAS_STYLUS2		0x02
 | 
				
			||||||
 | 
					#define F_HAS_SCROLLWHEEL	0x04
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* device IDs */
 | 
				
			||||||
 | 
					#define STYLUS_DEVICE_ID	0x02
 | 
				
			||||||
 | 
					#define CURSOR_DEVICE_ID	0x06
 | 
				
			||||||
 | 
					#define ERASER_DEVICE_ID	0x0A
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum { STYLUS = 1, ERASER, CURSOR };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct {
 | 
				
			||||||
 | 
						int device_id;
 | 
				
			||||||
 | 
						int input_id;
 | 
				
			||||||
 | 
					} tools[] = {
 | 
				
			||||||
 | 
						{ 0, 0 },
 | 
				
			||||||
 | 
						{ STYLUS_DEVICE_ID, BTN_TOOL_PEN },
 | 
				
			||||||
 | 
						{ ERASER_DEVICE_ID, BTN_TOOL_RUBBER },
 | 
				
			||||||
 | 
						{ CURSOR_DEVICE_ID, BTN_TOOL_MOUSE },
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct wacom {
 | 
				
			||||||
 | 
						struct input_dev *dev;
 | 
				
			||||||
 | 
						struct completion cmd_done;
 | 
				
			||||||
 | 
						int result;
 | 
				
			||||||
 | 
						u8 expect;
 | 
				
			||||||
 | 
						u8 eraser_mask;
 | 
				
			||||||
 | 
						unsigned int extra_z_bits;
 | 
				
			||||||
 | 
						unsigned int flags;
 | 
				
			||||||
 | 
						unsigned int res_x, res_y;
 | 
				
			||||||
 | 
						unsigned int max_x, max_y;
 | 
				
			||||||
 | 
						unsigned int tool;
 | 
				
			||||||
 | 
						unsigned int idx;
 | 
				
			||||||
 | 
						u8 data[DATA_SIZE];
 | 
				
			||||||
 | 
						char phys[32];
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum {
 | 
				
			||||||
 | 
						MODEL_CINTIQ		= 0x504C, /* PL */
 | 
				
			||||||
 | 
						MODEL_CINTIQ2		= 0x4454, /* DT */
 | 
				
			||||||
 | 
						MODEL_DIGITIZER_II	= 0x5544, /* UD */
 | 
				
			||||||
 | 
						MODEL_GRAPHIRE		= 0x4554, /* ET */
 | 
				
			||||||
 | 
						MODEL_PENPARTNER	= 0x4354, /* CT */
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void wacom_handle_model_response(struct wacom *wacom)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int major_v, minor_v, r = 0;
 | 
				
			||||||
 | 
						char *p;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						p = strrchr(wacom->data, 'V');
 | 
				
			||||||
 | 
						if (p)
 | 
				
			||||||
 | 
							r = sscanf(p + 1, "%u.%u", &major_v, &minor_v);
 | 
				
			||||||
 | 
						if (r != 2)
 | 
				
			||||||
 | 
							major_v = minor_v = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch (wacom->data[2] << 8 | wacom->data[3]) {
 | 
				
			||||||
 | 
						case MODEL_CINTIQ:	/* UNTESTED */
 | 
				
			||||||
 | 
						case MODEL_CINTIQ2:
 | 
				
			||||||
 | 
							if ((wacom->data[2] << 8 | wacom->data[3]) == MODEL_CINTIQ) {
 | 
				
			||||||
 | 
								wacom->dev->name = "Wacom Cintiq";
 | 
				
			||||||
 | 
								wacom->dev->id.version = MODEL_CINTIQ;
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								wacom->dev->name = "Wacom Cintiq II";
 | 
				
			||||||
 | 
								wacom->dev->id.version = MODEL_CINTIQ2;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							wacom->res_x = 508;
 | 
				
			||||||
 | 
							wacom->res_y = 508;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							switch (wacom->data[5] << 8 | wacom->data[6]) {
 | 
				
			||||||
 | 
							case 0x3731: /* PL-710 */
 | 
				
			||||||
 | 
								wacom->res_x = 2540;
 | 
				
			||||||
 | 
								wacom->res_y = 2540;
 | 
				
			||||||
 | 
								/* fall through */
 | 
				
			||||||
 | 
							case 0x3535: /* PL-550 */
 | 
				
			||||||
 | 
							case 0x3830: /* PL-800 */
 | 
				
			||||||
 | 
								wacom->extra_z_bits = 2;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							wacom->flags = F_COVERS_SCREEN;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case MODEL_PENPARTNER:
 | 
				
			||||||
 | 
							wacom->dev->name = "Wacom Penpartner";
 | 
				
			||||||
 | 
							wacom->dev->id.version = MODEL_PENPARTNER;
 | 
				
			||||||
 | 
							wacom->res_x = 1000;
 | 
				
			||||||
 | 
							wacom->res_y = 1000;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case MODEL_GRAPHIRE:
 | 
				
			||||||
 | 
							wacom->dev->name = "Wacom Graphire";
 | 
				
			||||||
 | 
							wacom->dev->id.version = MODEL_GRAPHIRE;
 | 
				
			||||||
 | 
							wacom->res_x = 1016;
 | 
				
			||||||
 | 
							wacom->res_y = 1016;
 | 
				
			||||||
 | 
							wacom->max_x = 5103;
 | 
				
			||||||
 | 
							wacom->max_y = 3711;
 | 
				
			||||||
 | 
							wacom->extra_z_bits = 2;
 | 
				
			||||||
 | 
							wacom->eraser_mask = 0x08;
 | 
				
			||||||
 | 
							wacom->flags = F_HAS_STYLUS2 | F_HAS_SCROLLWHEEL;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case MODEL_DIGITIZER_II:
 | 
				
			||||||
 | 
							wacom->dev->name = "Wacom Digitizer II";
 | 
				
			||||||
 | 
							wacom->dev->id.version = MODEL_DIGITIZER_II;
 | 
				
			||||||
 | 
							if (major_v == 1 && minor_v <= 2)
 | 
				
			||||||
 | 
								wacom->extra_z_bits = 0; /* UNTESTED */
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							dev_err(&wacom->dev->dev, "Unsupported Wacom model %s\n",
 | 
				
			||||||
 | 
								wacom->data);
 | 
				
			||||||
 | 
							wacom->result = -ENODEV;
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dev_info(&wacom->dev->dev, "%s tablet, version %u.%u\n",
 | 
				
			||||||
 | 
							 wacom->dev->name, major_v, minor_v);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void wacom_handle_configuration_response(struct wacom *wacom)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int r, skip;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dev_dbg(&wacom->dev->dev, "Configuration string: %s\n", wacom->data);
 | 
				
			||||||
 | 
						r = sscanf(wacom->data, "~R%x,%u,%u,%u,%u", &skip, &skip, &skip,
 | 
				
			||||||
 | 
							   &wacom->res_x, &wacom->res_y);
 | 
				
			||||||
 | 
						if (r != 5)
 | 
				
			||||||
 | 
							dev_warn(&wacom->dev->dev, "could not get resolution\n");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void wacom_handle_coordinates_response(struct wacom *wacom)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int r;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dev_dbg(&wacom->dev->dev, "Coordinates string: %s\n", wacom->data);
 | 
				
			||||||
 | 
						r = sscanf(wacom->data, "~C%u,%u", &wacom->max_x, &wacom->max_y);
 | 
				
			||||||
 | 
						if (r != 2)
 | 
				
			||||||
 | 
							dev_warn(&wacom->dev->dev, "could not get max coordinates\n");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void wacom_handle_response(struct wacom *wacom)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (wacom->data[0] != '~' || wacom->data[1] != wacom->expect) {
 | 
				
			||||||
 | 
							dev_err(&wacom->dev->dev,
 | 
				
			||||||
 | 
								"Wacom got an unexpected response: %s\n", wacom->data);
 | 
				
			||||||
 | 
							wacom->result = -EIO;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							wacom->result = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							switch (wacom->data[1]) {
 | 
				
			||||||
 | 
							case '#':
 | 
				
			||||||
 | 
								wacom_handle_model_response(wacom);
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case 'R':
 | 
				
			||||||
 | 
								wacom_handle_configuration_response(wacom);
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case 'C':
 | 
				
			||||||
 | 
								wacom_handle_coordinates_response(wacom);
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						complete(&wacom->cmd_done);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void wacom_handle_packet(struct wacom *wacom)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						u8 in_proximity_p, stylus_p, button;
 | 
				
			||||||
 | 
						unsigned int tool;
 | 
				
			||||||
 | 
						int x, y, z;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						in_proximity_p = wacom->data[0] & 0x40;
 | 
				
			||||||
 | 
						stylus_p = wacom->data[0] & 0x20;
 | 
				
			||||||
 | 
						button = (wacom->data[3] & 0x78) >> 3;
 | 
				
			||||||
 | 
						x = (wacom->data[0] & 3) << 14 | wacom->data[1]<<7 | wacom->data[2];
 | 
				
			||||||
 | 
						y = (wacom->data[3] & 3) << 14 | wacom->data[4]<<7 | wacom->data[5];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (in_proximity_p && stylus_p) {
 | 
				
			||||||
 | 
							z = wacom->data[6] & 0x7f;
 | 
				
			||||||
 | 
							if (wacom->extra_z_bits >= 1)
 | 
				
			||||||
 | 
								z = z << 1 | (wacom->data[3] & 0x4) >> 2;
 | 
				
			||||||
 | 
							if (wacom->extra_z_bits > 1)
 | 
				
			||||||
 | 
								z = z << 1 | (wacom->data[0] & 0x4) >> 2;
 | 
				
			||||||
 | 
							z = z ^ (0x40 << wacom->extra_z_bits);
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							z = -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (stylus_p)
 | 
				
			||||||
 | 
							tool = (button & wacom->eraser_mask) ? ERASER : STYLUS;
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							tool = CURSOR;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (tool != wacom->tool && wacom->tool != 0) {
 | 
				
			||||||
 | 
							input_report_key(wacom->dev, tools[wacom->tool].input_id, 0);
 | 
				
			||||||
 | 
							input_sync(wacom->dev);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						wacom->tool = tool;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						input_report_key(wacom->dev, tools[tool].input_id, in_proximity_p);
 | 
				
			||||||
 | 
						input_report_abs(wacom->dev, ABS_MISC,
 | 
				
			||||||
 | 
								 in_proximity_p ? tools[tool].device_id : 0);
 | 
				
			||||||
 | 
						input_report_abs(wacom->dev, ABS_X, x);
 | 
				
			||||||
 | 
						input_report_abs(wacom->dev, ABS_Y, y);
 | 
				
			||||||
 | 
						input_report_abs(wacom->dev, ABS_PRESSURE, z);
 | 
				
			||||||
 | 
						if (stylus_p) {
 | 
				
			||||||
 | 
							input_report_key(wacom->dev, BTN_TOUCH, button & 1);
 | 
				
			||||||
 | 
							input_report_key(wacom->dev, BTN_STYLUS, button & 2);
 | 
				
			||||||
 | 
							input_report_key(wacom->dev, BTN_STYLUS2, button & 4);
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							input_report_key(wacom->dev, BTN_LEFT, button & 1);
 | 
				
			||||||
 | 
							input_report_key(wacom->dev, BTN_RIGHT, button & 2);
 | 
				
			||||||
 | 
							input_report_key(wacom->dev, BTN_MIDDLE, button & 4);
 | 
				
			||||||
 | 
							/* handle relative wheel for non-stylus device */
 | 
				
			||||||
 | 
							z = (wacom->data[6] & 0x30) >> 4;
 | 
				
			||||||
 | 
							if (wacom->data[6] & 0x40)
 | 
				
			||||||
 | 
								z = -z;
 | 
				
			||||||
 | 
							input_report_rel(wacom->dev, REL_WHEEL, z);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						input_sync(wacom->dev);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void wacom_clear_data_buf(struct wacom *wacom)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						memset(wacom->data, 0, DATA_SIZE);
 | 
				
			||||||
 | 
						wacom->idx = 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static irqreturn_t wacom_interrupt(struct serio *serio, unsigned char data,
 | 
				
			||||||
 | 
									   unsigned int flags)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct wacom *wacom = serio_get_drvdata(serio);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (data & 0x80)
 | 
				
			||||||
 | 
							wacom->idx = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * We're either expecting a carriage return-terminated ASCII
 | 
				
			||||||
 | 
						 * response string, or a seven-byte packet with the MSB set on
 | 
				
			||||||
 | 
						 * the first byte.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * Note however that some tablets (the PenPartner, for
 | 
				
			||||||
 | 
						 * example) don't send a carriage return at the end of a
 | 
				
			||||||
 | 
						 * command.  We handle these by waiting for timeout.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						if (data == '\r' && !(wacom->data[0] & 0x80)) {
 | 
				
			||||||
 | 
							wacom_handle_response(wacom);
 | 
				
			||||||
 | 
							wacom_clear_data_buf(wacom);
 | 
				
			||||||
 | 
							return IRQ_HANDLED;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Leave place for 0 termination */
 | 
				
			||||||
 | 
						if (wacom->idx > (DATA_SIZE - 2)) {
 | 
				
			||||||
 | 
							dev_dbg(&wacom->dev->dev,
 | 
				
			||||||
 | 
								"throwing away %d bytes of garbage\n", wacom->idx);
 | 
				
			||||||
 | 
							wacom_clear_data_buf(wacom);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						wacom->data[wacom->idx++] = data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (wacom->idx == PACKET_LENGTH && (wacom->data[0] & 0x80)) {
 | 
				
			||||||
 | 
							wacom_handle_packet(wacom);
 | 
				
			||||||
 | 
							wacom_clear_data_buf(wacom);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return IRQ_HANDLED;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void wacom_disconnect(struct serio *serio)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct wacom *wacom = serio_get_drvdata(serio);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						serio_close(serio);
 | 
				
			||||||
 | 
						serio_set_drvdata(serio, NULL);
 | 
				
			||||||
 | 
						input_unregister_device(wacom->dev);
 | 
				
			||||||
 | 
						kfree(wacom);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int wacom_send(struct serio *serio, const u8 *command)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int err = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (; !err && *command; command++)
 | 
				
			||||||
 | 
							err = serio_write(serio, *command);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return err;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int wacom_send_setup_string(struct wacom *wacom, struct serio *serio)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						const u8 *cmd;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch (wacom->dev->id.version) {
 | 
				
			||||||
 | 
						case MODEL_CINTIQ:	/* UNTESTED */
 | 
				
			||||||
 | 
							cmd = COMMAND_ORIGIN_IN_UPPER_LEFT
 | 
				
			||||||
 | 
								COMMAND_TRANSMIT_AT_MAX_RATE
 | 
				
			||||||
 | 
								COMMAND_ENABLE_CONTINUOUS_MODE
 | 
				
			||||||
 | 
								COMMAND_START_SENDING_PACKETS;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case MODEL_PENPARTNER:
 | 
				
			||||||
 | 
							cmd = COMMAND_ENABLE_PRESSURE_MODE
 | 
				
			||||||
 | 
								COMMAND_START_SENDING_PACKETS;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							cmd = COMMAND_MULTI_MODE_INPUT
 | 
				
			||||||
 | 
								COMMAND_ORIGIN_IN_UPPER_LEFT
 | 
				
			||||||
 | 
								COMMAND_ENABLE_ALL_MACRO_BUTTONS
 | 
				
			||||||
 | 
								COMMAND_DISABLE_GROUP_1_MACRO_BUTTONS
 | 
				
			||||||
 | 
								COMMAND_TRANSMIT_AT_MAX_RATE
 | 
				
			||||||
 | 
								COMMAND_DISABLE_INCREMENTAL_MODE
 | 
				
			||||||
 | 
								COMMAND_ENABLE_CONTINUOUS_MODE
 | 
				
			||||||
 | 
								COMMAND_Z_FILTER
 | 
				
			||||||
 | 
								COMMAND_START_SENDING_PACKETS;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return wacom_send(serio, cmd);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int wacom_send_and_wait(struct wacom *wacom, struct serio *serio,
 | 
				
			||||||
 | 
								       const u8 *cmd, const char *desc)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int err;
 | 
				
			||||||
 | 
						unsigned long u;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						wacom->expect = cmd[1];
 | 
				
			||||||
 | 
						init_completion(&wacom->cmd_done);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err = wacom_send(serio, cmd);
 | 
				
			||||||
 | 
						if (err)
 | 
				
			||||||
 | 
							return err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						u = wait_for_completion_timeout(&wacom->cmd_done, HZ);
 | 
				
			||||||
 | 
						if (u == 0) {
 | 
				
			||||||
 | 
							/* Timeout, process what we've received. */
 | 
				
			||||||
 | 
							wacom_handle_response(wacom);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						wacom->expect = 0;
 | 
				
			||||||
 | 
						return wacom->result;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int wacom_setup(struct wacom *wacom, struct serio *serio)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Note that setting the link speed is the job of inputattach.
 | 
				
			||||||
 | 
						 * We assume that reset negotiation has already happened,
 | 
				
			||||||
 | 
						 * here. */
 | 
				
			||||||
 | 
						err = wacom_send_and_wait(wacom, serio, REQUEST_MODEL_AND_ROM_VERSION,
 | 
				
			||||||
 | 
									  "model and version");
 | 
				
			||||||
 | 
						if (err)
 | 
				
			||||||
 | 
							return err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!(wacom->res_x && wacom->res_y)) {
 | 
				
			||||||
 | 
							err = wacom_send_and_wait(wacom, serio,
 | 
				
			||||||
 | 
										  REQUEST_CONFIGURATION_STRING,
 | 
				
			||||||
 | 
										  "configuration string");
 | 
				
			||||||
 | 
							if (err)
 | 
				
			||||||
 | 
								return err;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!(wacom->max_x && wacom->max_y)) {
 | 
				
			||||||
 | 
							err = wacom_send_and_wait(wacom, serio,
 | 
				
			||||||
 | 
										  REQUEST_MAX_COORDINATES,
 | 
				
			||||||
 | 
										  "coordinates string");
 | 
				
			||||||
 | 
							if (err)
 | 
				
			||||||
 | 
								return err;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return wacom_send_setup_string(wacom, serio);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int wacom_connect(struct serio *serio, struct serio_driver *drv)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct wacom *wacom;
 | 
				
			||||||
 | 
						struct input_dev *input_dev;
 | 
				
			||||||
 | 
						int err = -ENOMEM;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						wacom = kzalloc(sizeof(struct wacom), GFP_KERNEL);
 | 
				
			||||||
 | 
						input_dev = input_allocate_device();
 | 
				
			||||||
 | 
						if (!wacom || !input_dev)
 | 
				
			||||||
 | 
							goto free_device;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						wacom->dev = input_dev;
 | 
				
			||||||
 | 
						wacom->extra_z_bits = 1;
 | 
				
			||||||
 | 
						wacom->eraser_mask = 0x04;
 | 
				
			||||||
 | 
						wacom->tool = wacom->idx = 0;
 | 
				
			||||||
 | 
						snprintf(wacom->phys, sizeof(wacom->phys), "%s/input0", serio->phys);
 | 
				
			||||||
 | 
						input_dev->phys = wacom->phys;
 | 
				
			||||||
 | 
						input_dev->id.bustype = BUS_RS232;
 | 
				
			||||||
 | 
						input_dev->id.vendor  = SERIO_WACOM_IV;
 | 
				
			||||||
 | 
						input_dev->id.product = serio->id.extra;
 | 
				
			||||||
 | 
						input_dev->dev.parent = &serio->dev;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						input_dev->evbit[0] =
 | 
				
			||||||
 | 
							BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS) | BIT_MASK(EV_REL);
 | 
				
			||||||
 | 
						set_bit(ABS_MISC, input_dev->absbit);
 | 
				
			||||||
 | 
						set_bit(BTN_TOOL_PEN, input_dev->keybit);
 | 
				
			||||||
 | 
						set_bit(BTN_TOOL_RUBBER, input_dev->keybit);
 | 
				
			||||||
 | 
						set_bit(BTN_TOOL_MOUSE, input_dev->keybit);
 | 
				
			||||||
 | 
						set_bit(BTN_TOUCH, input_dev->keybit);
 | 
				
			||||||
 | 
						set_bit(BTN_STYLUS, input_dev->keybit);
 | 
				
			||||||
 | 
						set_bit(BTN_LEFT, input_dev->keybit);
 | 
				
			||||||
 | 
						set_bit(BTN_RIGHT, input_dev->keybit);
 | 
				
			||||||
 | 
						set_bit(BTN_MIDDLE, input_dev->keybit);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						serio_set_drvdata(serio, wacom);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err = serio_open(serio, drv);
 | 
				
			||||||
 | 
						if (err)
 | 
				
			||||||
 | 
							goto free_device;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err = wacom_setup(wacom, serio);
 | 
				
			||||||
 | 
						if (err)
 | 
				
			||||||
 | 
							goto close_serio;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
 | 
				
			||||||
 | 
						if (!(wacom->flags & F_COVERS_SCREEN))
 | 
				
			||||||
 | 
							__set_bit(INPUT_PROP_POINTER, input_dev->propbit);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (wacom->flags & F_HAS_STYLUS2)
 | 
				
			||||||
 | 
							__set_bit(BTN_STYLUS2, input_dev->keybit);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (wacom->flags & F_HAS_SCROLLWHEEL)
 | 
				
			||||||
 | 
							__set_bit(REL_WHEEL, input_dev->relbit);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						input_abs_set_res(wacom->dev, ABS_X, wacom->res_x);
 | 
				
			||||||
 | 
						input_abs_set_res(wacom->dev, ABS_Y, wacom->res_y);
 | 
				
			||||||
 | 
						input_set_abs_params(wacom->dev, ABS_X, 0, wacom->max_x, 0, 0);
 | 
				
			||||||
 | 
						input_set_abs_params(wacom->dev, ABS_Y, 0, wacom->max_y, 0, 0);
 | 
				
			||||||
 | 
						input_set_abs_params(wacom->dev, ABS_PRESSURE, -1,
 | 
				
			||||||
 | 
								     (1 << (7 + wacom->extra_z_bits)) - 1, 0, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err = input_register_device(wacom->dev);
 | 
				
			||||||
 | 
						if (err)
 | 
				
			||||||
 | 
							goto close_serio;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					close_serio:
 | 
				
			||||||
 | 
						serio_close(serio);
 | 
				
			||||||
 | 
					free_device:
 | 
				
			||||||
 | 
						serio_set_drvdata(serio, NULL);
 | 
				
			||||||
 | 
						input_free_device(input_dev);
 | 
				
			||||||
 | 
						kfree(wacom);
 | 
				
			||||||
 | 
						return err;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct serio_device_id wacom_serio_ids[] = {
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							.type	= SERIO_RS232,
 | 
				
			||||||
 | 
							.proto	= SERIO_WACOM_IV,
 | 
				
			||||||
 | 
							.id	= SERIO_ANY,
 | 
				
			||||||
 | 
							.extra	= SERIO_ANY,
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						{ 0 }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					MODULE_DEVICE_TABLE(serio, wacom_serio_ids);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct serio_driver wacom_drv = {
 | 
				
			||||||
 | 
						.driver		= {
 | 
				
			||||||
 | 
							.name	= "wacom_serial4",
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						.description	= "Wacom protocol 4 serial tablet driver",
 | 
				
			||||||
 | 
						.id_table	= wacom_serio_ids,
 | 
				
			||||||
 | 
						.interrupt	= wacom_interrupt,
 | 
				
			||||||
 | 
						.connect	= wacom_connect,
 | 
				
			||||||
 | 
						.disconnect	= wacom_disconnect,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module_serio_driver(wacom_drv);
 | 
				
			||||||
| 
						 | 
					@ -471,6 +471,18 @@ config TOUCHSCREEN_HP7XX
 | 
				
			||||||
	  To compile this driver as a module, choose M here: the
 | 
						  To compile this driver as a module, choose M here: the
 | 
				
			||||||
	  module will be called jornada720_ts.
 | 
						  module will be called jornada720_ts.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					config TOUCHSCREEN_IPAQ_MICRO
 | 
				
			||||||
 | 
						tristate "HP iPAQ Atmel Micro ASIC touchscreen"
 | 
				
			||||||
 | 
						depends on MFD_IPAQ_MICRO
 | 
				
			||||||
 | 
						help
 | 
				
			||||||
 | 
						  Say Y here to enable support for the touchscreen attached to
 | 
				
			||||||
 | 
						  the Atmel Micro peripheral controller on iPAQ h3100/h3600/h3700
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						  If unsure, say N.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						  To compile this driver as a module, choose M here: the
 | 
				
			||||||
 | 
						  module will be called ipaq-micro-ts.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
config TOUCHSCREEN_HTCPEN
 | 
					config TOUCHSCREEN_HTCPEN
 | 
				
			||||||
	tristate "HTC Shift X9500 touchscreen"
 | 
						tristate "HTC Shift X9500 touchscreen"
 | 
				
			||||||
	depends on ISA
 | 
						depends on ISA
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -46,6 +46,7 @@ obj-$(CONFIG_TOUCHSCREEN_MTOUCH)	+= mtouch.o
 | 
				
			||||||
obj-$(CONFIG_TOUCHSCREEN_MK712)		+= mk712.o
 | 
					obj-$(CONFIG_TOUCHSCREEN_MK712)		+= mk712.o
 | 
				
			||||||
obj-$(CONFIG_TOUCHSCREEN_HP600)		+= hp680_ts_input.o
 | 
					obj-$(CONFIG_TOUCHSCREEN_HP600)		+= hp680_ts_input.o
 | 
				
			||||||
obj-$(CONFIG_TOUCHSCREEN_HP7XX)		+= jornada720_ts.o
 | 
					obj-$(CONFIG_TOUCHSCREEN_HP7XX)		+= jornada720_ts.o
 | 
				
			||||||
 | 
					obj-$(CONFIG_TOUCHSCREEN_IPAQ_MICRO)	+= ipaq-micro-ts.o
 | 
				
			||||||
obj-$(CONFIG_TOUCHSCREEN_HTCPEN)	+= htcpen.o
 | 
					obj-$(CONFIG_TOUCHSCREEN_HTCPEN)	+= htcpen.o
 | 
				
			||||||
obj-$(CONFIG_TOUCHSCREEN_USB_COMPOSITE)	+= usbtouchscreen.o
 | 
					obj-$(CONFIG_TOUCHSCREEN_USB_COMPOSITE)	+= usbtouchscreen.o
 | 
				
			||||||
obj-$(CONFIG_TOUCHSCREEN_PCAP)		+= pcap_ts.o
 | 
					obj-$(CONFIG_TOUCHSCREEN_PCAP)		+= pcap_ts.o
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1302,8 +1302,10 @@ static int ads7846_probe(struct spi_device *spi)
 | 
				
			||||||
	pdata = dev_get_platdata(&spi->dev);
 | 
						pdata = dev_get_platdata(&spi->dev);
 | 
				
			||||||
	if (!pdata) {
 | 
						if (!pdata) {
 | 
				
			||||||
		pdata = ads7846_probe_dt(&spi->dev);
 | 
							pdata = ads7846_probe_dt(&spi->dev);
 | 
				
			||||||
		if (IS_ERR(pdata))
 | 
							if (IS_ERR(pdata)) {
 | 
				
			||||||
			return PTR_ERR(pdata);
 | 
								err = PTR_ERR(pdata);
 | 
				
			||||||
 | 
								goto err_free_mem;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ts->model = pdata->model ? : 7846;
 | 
						ts->model = pdata->model ? : 7846;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							| 
						 | 
					@ -733,7 +733,6 @@ edt_ft5x06_ts_prepare_debugfs(struct edt_ft5x06_ts_data *tsdata,
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
edt_ft5x06_ts_teardown_debugfs(struct edt_ft5x06_ts_data *tsdata)
 | 
					edt_ft5x06_ts_teardown_debugfs(struct edt_ft5x06_ts_data *tsdata)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (tsdata->debug_dir)
 | 
					 | 
				
			||||||
	debugfs_remove_recursive(tsdata->debug_dir);
 | 
						debugfs_remove_recursive(tsdata->debug_dir);
 | 
				
			||||||
	kfree(tsdata->raw_buffer);
 | 
						kfree(tsdata->raw_buffer);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										166
									
								
								drivers/input/touchscreen/ipaq-micro-ts.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										166
									
								
								drivers/input/touchscreen/ipaq-micro-ts.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,166 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * 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.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * h3600 atmel micro companion support, touchscreen subdevice
 | 
				
			||||||
 | 
					 * Author : Alessandro Gardich <gremlin@gremlin.it>
 | 
				
			||||||
 | 
					 * Author : Dmitry Artamonow <mad_soft@inbox.ru>
 | 
				
			||||||
 | 
					 * Author : Linus Walleij <linus.walleij@linaro.org>
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <asm/byteorder.h>
 | 
				
			||||||
 | 
					#include <linux/module.h>
 | 
				
			||||||
 | 
					#include <linux/init.h>
 | 
				
			||||||
 | 
					#include <linux/interrupt.h>
 | 
				
			||||||
 | 
					#include <linux/pm.h>
 | 
				
			||||||
 | 
					#include <linux/delay.h>
 | 
				
			||||||
 | 
					#include <linux/device.h>
 | 
				
			||||||
 | 
					#include <linux/input.h>
 | 
				
			||||||
 | 
					#include <linux/platform_device.h>
 | 
				
			||||||
 | 
					#include <linux/slab.h>
 | 
				
			||||||
 | 
					#include <linux/mfd/ipaq-micro.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct touchscreen_data {
 | 
				
			||||||
 | 
						struct input_dev *input;
 | 
				
			||||||
 | 
						struct ipaq_micro *micro;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void micro_ts_receive(void *data, int len, unsigned char *msg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct touchscreen_data *ts = data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (len == 4) {
 | 
				
			||||||
 | 
							input_report_abs(ts->input, ABS_X,
 | 
				
			||||||
 | 
									 be16_to_cpup((__be16 *) &msg[2]));
 | 
				
			||||||
 | 
							input_report_abs(ts->input, ABS_Y,
 | 
				
			||||||
 | 
									 be16_to_cpup((__be16 *) &msg[0]));
 | 
				
			||||||
 | 
							input_report_key(ts->input, BTN_TOUCH, 1);
 | 
				
			||||||
 | 
							input_sync(ts->input);
 | 
				
			||||||
 | 
						} else if (len == 0) {
 | 
				
			||||||
 | 
							input_report_abs(ts->input, ABS_X, 0);
 | 
				
			||||||
 | 
							input_report_abs(ts->input, ABS_Y, 0);
 | 
				
			||||||
 | 
							input_report_key(ts->input, BTN_TOUCH, 0);
 | 
				
			||||||
 | 
							input_sync(ts->input);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void micro_ts_toggle_receive(struct touchscreen_data *ts, bool enable)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct ipaq_micro *micro = ts->micro;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						spin_lock_irq(µ->lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (enable) {
 | 
				
			||||||
 | 
							micro->ts = micro_ts_receive;
 | 
				
			||||||
 | 
							micro->ts_data = ts;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							micro->ts = NULL;
 | 
				
			||||||
 | 
							micro->ts_data = NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						spin_unlock_irq(&ts->micro->lock);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int micro_ts_open(struct input_dev *input)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct touchscreen_data *ts = input_get_drvdata(input);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						micro_ts_toggle_receive(ts, true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void micro_ts_close(struct input_dev *input)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct touchscreen_data *ts = input_get_drvdata(input);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						micro_ts_toggle_receive(ts, false);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int micro_ts_probe(struct platform_device *pdev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct ipaq_micro *micro = dev_get_drvdata(pdev->dev.parent);
 | 
				
			||||||
 | 
						struct touchscreen_data *ts;
 | 
				
			||||||
 | 
						int error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ts = devm_kzalloc(&pdev->dev, sizeof(*ts), GFP_KERNEL);
 | 
				
			||||||
 | 
						if (!ts)
 | 
				
			||||||
 | 
							return -ENOMEM;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ts->micro = micro;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ts->input = devm_input_allocate_device(&pdev->dev);
 | 
				
			||||||
 | 
						if (!ts->input) {
 | 
				
			||||||
 | 
							dev_err(&pdev->dev, "failed to allocate input device\n");
 | 
				
			||||||
 | 
							return -ENOMEM;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ts->input->name = "ipaq micro ts";
 | 
				
			||||||
 | 
						ts->input->open = micro_ts_open;
 | 
				
			||||||
 | 
						ts->input->close = micro_ts_close;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						input_set_drvdata(ts->input, ts);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						input_set_capability(ts->input, EV_KEY, BTN_TOUCH);
 | 
				
			||||||
 | 
						input_set_capability(ts->input, EV_ABS, ABS_X);
 | 
				
			||||||
 | 
						input_set_capability(ts->input, EV_ABS, ABS_Y);
 | 
				
			||||||
 | 
						input_set_abs_params(ts->input, ABS_X, 0, 1023, 0, 0);
 | 
				
			||||||
 | 
						input_set_abs_params(ts->input, ABS_Y, 0, 1023, 0, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						error = input_register_device(ts->input);
 | 
				
			||||||
 | 
						if (error) {
 | 
				
			||||||
 | 
							dev_err(&pdev->dev, "error registering touch input\n");
 | 
				
			||||||
 | 
							return error;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						platform_set_drvdata(pdev, ts);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dev_info(&pdev->dev, "iPAQ micro touchscreen\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef CONFIG_PM_SLEEP
 | 
				
			||||||
 | 
					static int micro_ts_suspend(struct device *dev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct touchscreen_data *ts = dev_get_drvdata(dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						micro_ts_toggle_receive(ts, false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int micro_ts_resume(struct device *dev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct touchscreen_data *ts = dev_get_drvdata(dev);
 | 
				
			||||||
 | 
						struct input_dev *input = ts->input;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mutex_lock(&input->mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (input->users)
 | 
				
			||||||
 | 
							micro_ts_toggle_receive(ts, true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mutex_unlock(&input->mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct dev_pm_ops micro_ts_dev_pm_ops = {
 | 
				
			||||||
 | 
						SET_SYSTEM_SLEEP_PM_OPS(micro_ts_suspend, micro_ts_resume)
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct platform_driver micro_ts_device_driver = {
 | 
				
			||||||
 | 
						.driver	= {
 | 
				
			||||||
 | 
							.name	= "ipaq-micro-ts",
 | 
				
			||||||
 | 
							.pm	= µ_ts_dev_pm_ops,
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						.probe	= micro_ts_probe,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					module_platform_driver(micro_ts_device_driver);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					MODULE_LICENSE("GPL");
 | 
				
			||||||
 | 
					MODULE_DESCRIPTION("driver for iPAQ Atmel micro touchscreen");
 | 
				
			||||||
 | 
					MODULE_ALIAS("platform:ipaq-micro-ts");
 | 
				
			||||||
| 
						 | 
					@ -36,7 +36,6 @@ struct jornada_ts {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void jornada720_ts_collect_data(struct jornada_ts *jornada_ts)
 | 
					static void jornada720_ts_collect_data(struct jornada_ts *jornada_ts)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* 3 low word X samples */
 | 
						/* 3 low word X samples */
 | 
				
			||||||
	jornada_ts->x_data[0] = jornada_ssp_byte(TXDUMMY);
 | 
						jornada_ts->x_data[0] = jornada_ssp_byte(TXDUMMY);
 | 
				
			||||||
	jornada_ts->x_data[1] = jornada_ssp_byte(TXDUMMY);
 | 
						jornada_ts->x_data[1] = jornada_ssp_byte(TXDUMMY);
 | 
				
			||||||
| 
						 | 
					@ -104,13 +103,13 @@ static int jornada720_ts_probe(struct platform_device *pdev)
 | 
				
			||||||
	struct input_dev *input_dev;
 | 
						struct input_dev *input_dev;
 | 
				
			||||||
	int error;
 | 
						int error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	jornada_ts = kzalloc(sizeof(struct jornada_ts), GFP_KERNEL);
 | 
						jornada_ts = devm_kzalloc(&pdev->dev, sizeof(*jornada_ts), GFP_KERNEL);
 | 
				
			||||||
	input_dev = input_allocate_device();
 | 
						if (!jornada_ts)
 | 
				
			||||||
 | 
							return -ENOMEM;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!jornada_ts || !input_dev) {
 | 
						input_dev = devm_input_allocate_device(&pdev->dev);
 | 
				
			||||||
		error = -ENOMEM;
 | 
						if (!input_dev)
 | 
				
			||||||
		goto fail1;
 | 
							return -ENOMEM;
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	platform_set_drvdata(pdev, jornada_ts);
 | 
						platform_set_drvdata(pdev, jornada_ts);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -126,36 +125,18 @@ static int jornada720_ts_probe(struct platform_device *pdev)
 | 
				
			||||||
	input_set_abs_params(input_dev, ABS_X, 270, 3900, 0, 0);
 | 
						input_set_abs_params(input_dev, ABS_X, 270, 3900, 0, 0);
 | 
				
			||||||
	input_set_abs_params(input_dev, ABS_Y, 180, 3700, 0, 0);
 | 
						input_set_abs_params(input_dev, ABS_Y, 180, 3700, 0, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	error = request_irq(IRQ_GPIO9,
 | 
						error = devm_request_irq(&pdev->dev, IRQ_GPIO9,
 | 
				
			||||||
				 jornada720_ts_interrupt,
 | 
									 jornada720_ts_interrupt,
 | 
				
			||||||
				 IRQF_TRIGGER_RISING,
 | 
									 IRQF_TRIGGER_RISING,
 | 
				
			||||||
				 "HP7XX Touchscreen driver", pdev);
 | 
									 "HP7XX Touchscreen driver", pdev);
 | 
				
			||||||
	if (error) {
 | 
						if (error) {
 | 
				
			||||||
		printk(KERN_INFO "HP7XX TS : Unable to acquire irq!\n");
 | 
							dev_err(&pdev->dev, "HP7XX TS : Unable to acquire irq!\n");
 | 
				
			||||||
		goto fail1;
 | 
							return error;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	error = input_register_device(jornada_ts->dev);
 | 
						error = input_register_device(jornada_ts->dev);
 | 
				
			||||||
	if (error)
 | 
						if (error)
 | 
				
			||||||
		goto fail2;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 fail2:
 | 
					 | 
				
			||||||
	free_irq(IRQ_GPIO9, pdev);
 | 
					 | 
				
			||||||
 fail1:
 | 
					 | 
				
			||||||
	input_free_device(input_dev);
 | 
					 | 
				
			||||||
	kfree(jornada_ts);
 | 
					 | 
				
			||||||
		return error;
 | 
							return error;
 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int jornada720_ts_remove(struct platform_device *pdev)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct jornada_ts *jornada_ts = platform_get_drvdata(pdev);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	free_irq(IRQ_GPIO9, pdev);
 | 
					 | 
				
			||||||
	input_unregister_device(jornada_ts->dev);
 | 
					 | 
				
			||||||
	kfree(jornada_ts);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -165,7 +146,6 @@ MODULE_ALIAS("platform:jornada_ts");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct platform_driver jornada720_ts_driver = {
 | 
					static struct platform_driver jornada720_ts_driver = {
 | 
				
			||||||
	.probe		= jornada720_ts_probe,
 | 
						.probe		= jornada720_ts_probe,
 | 
				
			||||||
	.remove		= jornada720_ts_remove,
 | 
					 | 
				
			||||||
	.driver		= {
 | 
						.driver		= {
 | 
				
			||||||
		.name	= "jornada_ts",
 | 
							.name	= "jornada_ts",
 | 
				
			||||||
		.owner	= THIS_MODULE,
 | 
							.owner	= THIS_MODULE,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -248,8 +248,7 @@ static int mcs5000_ts_probe(struct i2c_client *client,
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_PM
 | 
					static int __maybe_unused mcs5000_ts_suspend(struct device *dev)
 | 
				
			||||||
static int mcs5000_ts_suspend(struct device *dev)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct i2c_client *client = to_i2c_client(dev);
 | 
						struct i2c_client *client = to_i2c_client(dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -259,7 +258,7 @@ static int mcs5000_ts_suspend(struct device *dev)
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int mcs5000_ts_resume(struct device *dev)
 | 
					static int __maybe_unused mcs5000_ts_resume(struct device *dev)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct i2c_client *client = to_i2c_client(dev);
 | 
						struct i2c_client *client = to_i2c_client(dev);
 | 
				
			||||||
	struct mcs5000_ts_data *data = i2c_get_clientdata(client);
 | 
						struct mcs5000_ts_data *data = i2c_get_clientdata(client);
 | 
				
			||||||
| 
						 | 
					@ -269,7 +268,6 @@ static int mcs5000_ts_resume(struct device *dev)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
static SIMPLE_DEV_PM_OPS(mcs5000_ts_pm, mcs5000_ts_suspend, mcs5000_ts_resume);
 | 
					static SIMPLE_DEV_PM_OPS(mcs5000_ts_pm, mcs5000_ts_suspend, mcs5000_ts_resume);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -23,22 +23,51 @@
 | 
				
			||||||
#include <linux/slab.h>
 | 
					#include <linux/slab.h>
 | 
				
			||||||
#include <linux/i2c.h>
 | 
					#include <linux/i2c.h>
 | 
				
			||||||
#include <linux/input.h>
 | 
					#include <linux/input.h>
 | 
				
			||||||
 | 
					#include <linux/input/mt.h>
 | 
				
			||||||
#include <linux/input/pixcir_ts.h>
 | 
					#include <linux/input/pixcir_ts.h>
 | 
				
			||||||
#include <linux/gpio.h>
 | 
					#include <linux/gpio.h>
 | 
				
			||||||
 | 
					#include <linux/of.h>
 | 
				
			||||||
 | 
					#include <linux/of_gpio.h>
 | 
				
			||||||
 | 
					#include <linux/of_device.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define PIXCIR_MAX_SLOTS       5 /* Max fingers supported by driver */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct pixcir_i2c_ts_data {
 | 
					struct pixcir_i2c_ts_data {
 | 
				
			||||||
	struct i2c_client *client;
 | 
						struct i2c_client *client;
 | 
				
			||||||
	struct input_dev *input;
 | 
						struct input_dev *input;
 | 
				
			||||||
	const struct pixcir_ts_platform_data *chip;
 | 
						const struct pixcir_ts_platform_data *pdata;
 | 
				
			||||||
	bool running;
 | 
						bool running;
 | 
				
			||||||
 | 
						int max_fingers;	/* Max fingers supported in this instance */
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void pixcir_ts_poscheck(struct pixcir_i2c_ts_data *data)
 | 
					struct pixcir_touch {
 | 
				
			||||||
 | 
						int x;
 | 
				
			||||||
 | 
						int y;
 | 
				
			||||||
 | 
						int id;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct pixcir_report_data {
 | 
				
			||||||
 | 
						int num_touches;
 | 
				
			||||||
 | 
						struct pixcir_touch touches[PIXCIR_MAX_SLOTS];
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void pixcir_ts_parse(struct pixcir_i2c_ts_data *tsdata,
 | 
				
			||||||
 | 
								    struct pixcir_report_data *report)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct pixcir_i2c_ts_data *tsdata = data;
 | 
						u8 rdbuf[2 + PIXCIR_MAX_SLOTS * 5];
 | 
				
			||||||
	u8 rdbuf[10], wrbuf[1] = { 0 };
 | 
						u8 wrbuf[1] = { 0 };
 | 
				
			||||||
 | 
						u8 *bufptr;
 | 
				
			||||||
	u8 touch;
 | 
						u8 touch;
 | 
				
			||||||
	int ret;
 | 
						int ret, i;
 | 
				
			||||||
 | 
						int readsize;
 | 
				
			||||||
 | 
						const struct pixcir_i2c_chip_data *chip = &tsdata->pdata->chip;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						memset(report, 0, sizeof(struct pixcir_report_data));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						i = chip->has_hw_ids ? 1 : 0;
 | 
				
			||||||
 | 
						readsize = 2 + tsdata->max_fingers * (4 + i);
 | 
				
			||||||
 | 
						if (readsize > sizeof(rdbuf))
 | 
				
			||||||
 | 
							readsize = sizeof(rdbuf);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ret = i2c_master_send(tsdata->client, wrbuf, sizeof(wrbuf));
 | 
						ret = i2c_master_send(tsdata->client, wrbuf, sizeof(wrbuf));
 | 
				
			||||||
	if (ret != sizeof(wrbuf)) {
 | 
						if (ret != sizeof(wrbuf)) {
 | 
				
			||||||
| 
						 | 
					@ -48,7 +77,7 @@ static void pixcir_ts_poscheck(struct pixcir_i2c_ts_data *data)
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ret = i2c_master_recv(tsdata->client, rdbuf, sizeof(rdbuf));
 | 
						ret = i2c_master_recv(tsdata->client, rdbuf, readsize);
 | 
				
			||||||
	if (ret != sizeof(rdbuf)) {
 | 
						if (ret != sizeof(rdbuf)) {
 | 
				
			||||||
		dev_err(&tsdata->client->dev,
 | 
							dev_err(&tsdata->client->dev,
 | 
				
			||||||
			"%s: i2c_master_recv failed(), ret=%d\n",
 | 
								"%s: i2c_master_recv failed(), ret=%d\n",
 | 
				
			||||||
| 
						 | 
					@ -56,45 +85,103 @@ static void pixcir_ts_poscheck(struct pixcir_i2c_ts_data *data)
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	touch = rdbuf[0];
 | 
						touch = rdbuf[0] & 0x7;
 | 
				
			||||||
	if (touch) {
 | 
						if (touch > tsdata->max_fingers)
 | 
				
			||||||
		u16 posx1 = (rdbuf[3] << 8) | rdbuf[2];
 | 
							touch = tsdata->max_fingers;
 | 
				
			||||||
		u16 posy1 = (rdbuf[5] << 8) | rdbuf[4];
 | 
					 | 
				
			||||||
		u16 posx2 = (rdbuf[7] << 8) | rdbuf[6];
 | 
					 | 
				
			||||||
		u16 posy2 = (rdbuf[9] << 8) | rdbuf[8];
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		input_report_key(tsdata->input, BTN_TOUCH, 1);
 | 
						report->num_touches = touch;
 | 
				
			||||||
		input_report_abs(tsdata->input, ABS_X, posx1);
 | 
						bufptr = &rdbuf[2];
 | 
				
			||||||
		input_report_abs(tsdata->input, ABS_Y, posy1);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		input_report_abs(tsdata->input, ABS_MT_POSITION_X, posx1);
 | 
						for (i = 0; i < touch; i++) {
 | 
				
			||||||
		input_report_abs(tsdata->input, ABS_MT_POSITION_Y, posy1);
 | 
							report->touches[i].x = (bufptr[1] << 8) | bufptr[0];
 | 
				
			||||||
		input_mt_sync(tsdata->input);
 | 
							report->touches[i].y = (bufptr[3] << 8) | bufptr[2];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (touch == 2) {
 | 
							if (chip->has_hw_ids) {
 | 
				
			||||||
			input_report_abs(tsdata->input,
 | 
								report->touches[i].id = bufptr[4];
 | 
				
			||||||
					 ABS_MT_POSITION_X, posx2);
 | 
								bufptr = bufptr + 5;
 | 
				
			||||||
			input_report_abs(tsdata->input,
 | 
							} else {
 | 
				
			||||||
					 ABS_MT_POSITION_Y, posy2);
 | 
								bufptr = bufptr + 4;
 | 
				
			||||||
			input_mt_sync(tsdata->input);
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void pixcir_ts_report(struct pixcir_i2c_ts_data *ts,
 | 
				
			||||||
 | 
								     struct pixcir_report_data *report)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct input_mt_pos pos[PIXCIR_MAX_SLOTS];
 | 
				
			||||||
 | 
						int slots[PIXCIR_MAX_SLOTS];
 | 
				
			||||||
 | 
						struct pixcir_touch *touch;
 | 
				
			||||||
 | 
						int n, i, slot;
 | 
				
			||||||
 | 
						struct device *dev = &ts->client->dev;
 | 
				
			||||||
 | 
						const struct pixcir_i2c_chip_data *chip = &ts->pdata->chip;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						n = report->num_touches;
 | 
				
			||||||
 | 
						if (n > PIXCIR_MAX_SLOTS)
 | 
				
			||||||
 | 
							n = PIXCIR_MAX_SLOTS;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!chip->has_hw_ids) {
 | 
				
			||||||
 | 
							for (i = 0; i < n; i++) {
 | 
				
			||||||
 | 
								touch = &report->touches[i];
 | 
				
			||||||
 | 
								pos[i].x = touch->x;
 | 
				
			||||||
 | 
								pos[i].y = touch->y;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							input_mt_assign_slots(ts->input, slots, pos, n);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i < n; i++) {
 | 
				
			||||||
 | 
							touch = &report->touches[i];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (chip->has_hw_ids) {
 | 
				
			||||||
 | 
								slot = input_mt_get_slot_by_key(ts->input, touch->id);
 | 
				
			||||||
 | 
								if (slot < 0) {
 | 
				
			||||||
 | 
									dev_dbg(dev, "no free slot for id 0x%x\n",
 | 
				
			||||||
 | 
										touch->id);
 | 
				
			||||||
 | 
									continue;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
		input_report_key(tsdata->input, BTN_TOUCH, 0);
 | 
								slot = slots[i];
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	input_sync(tsdata->input);
 | 
							input_mt_slot(ts->input, slot);
 | 
				
			||||||
 | 
							input_mt_report_slot_state(ts->input,
 | 
				
			||||||
 | 
										   MT_TOOL_FINGER, true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							input_event(ts->input, EV_ABS, ABS_MT_POSITION_X, touch->x);
 | 
				
			||||||
 | 
							input_event(ts->input, EV_ABS, ABS_MT_POSITION_Y, touch->y);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							dev_dbg(dev, "%d: slot %d, x %d, y %d\n",
 | 
				
			||||||
 | 
								i, slot, touch->x, touch->y);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						input_mt_sync_frame(ts->input);
 | 
				
			||||||
 | 
						input_sync(ts->input);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static irqreturn_t pixcir_ts_isr(int irq, void *dev_id)
 | 
					static irqreturn_t pixcir_ts_isr(int irq, void *dev_id)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct pixcir_i2c_ts_data *tsdata = dev_id;
 | 
						struct pixcir_i2c_ts_data *tsdata = dev_id;
 | 
				
			||||||
	const struct pixcir_ts_platform_data *pdata = tsdata->chip;
 | 
						const struct pixcir_ts_platform_data *pdata = tsdata->pdata;
 | 
				
			||||||
 | 
						struct pixcir_report_data report;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	while (tsdata->running) {
 | 
						while (tsdata->running) {
 | 
				
			||||||
		pixcir_ts_poscheck(tsdata);
 | 
							/* parse packet */
 | 
				
			||||||
 | 
							pixcir_ts_parse(tsdata, &report);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (gpio_get_value(pdata->gpio_attb))
 | 
							/* report it */
 | 
				
			||||||
 | 
							pixcir_ts_report(tsdata, &report);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (gpio_get_value(pdata->gpio_attb)) {
 | 
				
			||||||
 | 
								if (report.num_touches) {
 | 
				
			||||||
 | 
									/*
 | 
				
			||||||
 | 
									 * Last report with no finger up?
 | 
				
			||||||
 | 
									 * Do it now then.
 | 
				
			||||||
 | 
									 */
 | 
				
			||||||
 | 
									input_mt_sync_frame(tsdata->input);
 | 
				
			||||||
 | 
									input_sync(tsdata->input);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		msleep(20);
 | 
							msleep(20);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -323,16 +410,69 @@ unlock:
 | 
				
			||||||
static SIMPLE_DEV_PM_OPS(pixcir_dev_pm_ops,
 | 
					static SIMPLE_DEV_PM_OPS(pixcir_dev_pm_ops,
 | 
				
			||||||
			 pixcir_i2c_ts_suspend, pixcir_i2c_ts_resume);
 | 
								 pixcir_i2c_ts_suspend, pixcir_i2c_ts_resume);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef CONFIG_OF
 | 
				
			||||||
 | 
					static const struct of_device_id pixcir_of_match[];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct pixcir_ts_platform_data *pixcir_parse_dt(struct device *dev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct pixcir_ts_platform_data *pdata;
 | 
				
			||||||
 | 
						struct device_node *np = dev->of_node;
 | 
				
			||||||
 | 
						const struct of_device_id *match;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						match = of_match_device(of_match_ptr(pixcir_of_match), dev);
 | 
				
			||||||
 | 
						if (!match)
 | 
				
			||||||
 | 
							return ERR_PTR(-EINVAL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
 | 
				
			||||||
 | 
						if (!pdata)
 | 
				
			||||||
 | 
							return ERR_PTR(-ENOMEM);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pdata->chip = *(const struct pixcir_i2c_chip_data *)match->data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pdata->gpio_attb = of_get_named_gpio(np, "attb-gpio", 0);
 | 
				
			||||||
 | 
						/* gpio_attb validity is checked in probe */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (of_property_read_u32(np, "touchscreen-size-x", &pdata->x_max)) {
 | 
				
			||||||
 | 
							dev_err(dev, "Failed to get touchscreen-size-x property\n");
 | 
				
			||||||
 | 
							return ERR_PTR(-EINVAL);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						pdata->x_max -= 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (of_property_read_u32(np, "touchscreen-size-y", &pdata->y_max)) {
 | 
				
			||||||
 | 
							dev_err(dev, "Failed to get touchscreen-size-y property\n");
 | 
				
			||||||
 | 
							return ERR_PTR(-EINVAL);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						pdata->y_max -= 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dev_dbg(dev, "%s: x %d, y %d, gpio %d\n", __func__,
 | 
				
			||||||
 | 
							pdata->x_max + 1, pdata->y_max + 1, pdata->gpio_attb);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return pdata;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					static struct pixcir_ts_platform_data *pixcir_parse_dt(struct device *dev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return ERR_PTR(-EINVAL);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int pixcir_i2c_ts_probe(struct i2c_client *client,
 | 
					static int pixcir_i2c_ts_probe(struct i2c_client *client,
 | 
				
			||||||
					 const struct i2c_device_id *id)
 | 
										 const struct i2c_device_id *id)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	const struct pixcir_ts_platform_data *pdata =
 | 
						const struct pixcir_ts_platform_data *pdata =
 | 
				
			||||||
			dev_get_platdata(&client->dev);
 | 
								dev_get_platdata(&client->dev);
 | 
				
			||||||
	struct device *dev = &client->dev;
 | 
						struct device *dev = &client->dev;
 | 
				
			||||||
 | 
						struct device_node *np = dev->of_node;
 | 
				
			||||||
	struct pixcir_i2c_ts_data *tsdata;
 | 
						struct pixcir_i2c_ts_data *tsdata;
 | 
				
			||||||
	struct input_dev *input;
 | 
						struct input_dev *input;
 | 
				
			||||||
	int error;
 | 
						int error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (np && !pdata) {
 | 
				
			||||||
 | 
							pdata = pixcir_parse_dt(dev);
 | 
				
			||||||
 | 
							if (IS_ERR(pdata))
 | 
				
			||||||
 | 
								return PTR_ERR(pdata);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!pdata) {
 | 
						if (!pdata) {
 | 
				
			||||||
		dev_err(&client->dev, "platform data not defined\n");
 | 
							dev_err(&client->dev, "platform data not defined\n");
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
| 
						 | 
					@ -343,6 +483,11 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!pdata->chip.max_fingers) {
 | 
				
			||||||
 | 
							dev_err(dev, "Invalid max_fingers in pdata\n");
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	tsdata = devm_kzalloc(dev, sizeof(*tsdata), GFP_KERNEL);
 | 
						tsdata = devm_kzalloc(dev, sizeof(*tsdata), GFP_KERNEL);
 | 
				
			||||||
	if (!tsdata)
 | 
						if (!tsdata)
 | 
				
			||||||
		return -ENOMEM;
 | 
							return -ENOMEM;
 | 
				
			||||||
| 
						 | 
					@ -355,7 +500,7 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	tsdata->client = client;
 | 
						tsdata->client = client;
 | 
				
			||||||
	tsdata->input = input;
 | 
						tsdata->input = input;
 | 
				
			||||||
	tsdata->chip = pdata;
 | 
						tsdata->pdata = pdata;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	input->name = client->name;
 | 
						input->name = client->name;
 | 
				
			||||||
	input->id.bustype = BUS_I2C;
 | 
						input->id.bustype = BUS_I2C;
 | 
				
			||||||
| 
						 | 
					@ -371,6 +516,20 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
 | 
				
			||||||
	input_set_abs_params(input, ABS_MT_POSITION_X, 0, pdata->x_max, 0, 0);
 | 
						input_set_abs_params(input, ABS_MT_POSITION_X, 0, pdata->x_max, 0, 0);
 | 
				
			||||||
	input_set_abs_params(input, ABS_MT_POSITION_Y, 0, pdata->y_max, 0, 0);
 | 
						input_set_abs_params(input, ABS_MT_POSITION_Y, 0, pdata->y_max, 0, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						tsdata->max_fingers = tsdata->pdata->chip.max_fingers;
 | 
				
			||||||
 | 
						if (tsdata->max_fingers > PIXCIR_MAX_SLOTS) {
 | 
				
			||||||
 | 
							tsdata->max_fingers = PIXCIR_MAX_SLOTS;
 | 
				
			||||||
 | 
							dev_info(dev, "Limiting maximum fingers to %d\n",
 | 
				
			||||||
 | 
								 tsdata->max_fingers);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						error = input_mt_init_slots(input, tsdata->max_fingers,
 | 
				
			||||||
 | 
									    INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED);
 | 
				
			||||||
 | 
						if (error) {
 | 
				
			||||||
 | 
							dev_err(dev, "Error initializing Multi-Touch slots\n");
 | 
				
			||||||
 | 
							return error;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	input_set_drvdata(input, tsdata);
 | 
						input_set_drvdata(input, tsdata);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	error = devm_gpio_request_one(dev, pdata->gpio_attb,
 | 
						error = devm_gpio_request_one(dev, pdata->gpio_attb,
 | 
				
			||||||
| 
						 | 
					@ -419,15 +578,36 @@ static int pixcir_i2c_ts_remove(struct i2c_client *client)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const struct i2c_device_id pixcir_i2c_ts_id[] = {
 | 
					static const struct i2c_device_id pixcir_i2c_ts_id[] = {
 | 
				
			||||||
	{ "pixcir_ts", 0 },
 | 
						{ "pixcir_ts", 0 },
 | 
				
			||||||
 | 
						{ "pixcir_tangoc", 0 },
 | 
				
			||||||
	{ }
 | 
						{ }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
MODULE_DEVICE_TABLE(i2c, pixcir_i2c_ts_id);
 | 
					MODULE_DEVICE_TABLE(i2c, pixcir_i2c_ts_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef CONFIG_OF
 | 
				
			||||||
 | 
					static const struct pixcir_i2c_chip_data pixcir_ts_data = {
 | 
				
			||||||
 | 
						.max_fingers = 2,
 | 
				
			||||||
 | 
						/* no hw id support */
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct pixcir_i2c_chip_data pixcir_tangoc_data = {
 | 
				
			||||||
 | 
						.max_fingers = 5,
 | 
				
			||||||
 | 
						.has_hw_ids = true,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct of_device_id pixcir_of_match[] = {
 | 
				
			||||||
 | 
						{ .compatible = "pixcir,pixcir_ts", .data = &pixcir_ts_data },
 | 
				
			||||||
 | 
						{ .compatible = "pixcir,pixcir_tangoc", .data = &pixcir_tangoc_data },
 | 
				
			||||||
 | 
						{ }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					MODULE_DEVICE_TABLE(of, pixcir_of_match);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct i2c_driver pixcir_i2c_ts_driver = {
 | 
					static struct i2c_driver pixcir_i2c_ts_driver = {
 | 
				
			||||||
	.driver = {
 | 
						.driver = {
 | 
				
			||||||
		.owner	= THIS_MODULE,
 | 
							.owner	= THIS_MODULE,
 | 
				
			||||||
		.name	= "pixcir_ts",
 | 
							.name	= "pixcir_ts",
 | 
				
			||||||
		.pm	= &pixcir_dev_pm_ops,
 | 
							.pm	= &pixcir_dev_pm_ops,
 | 
				
			||||||
 | 
							.of_match_table = of_match_ptr(pixcir_of_match),
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
	.probe		= pixcir_i2c_ts_probe,
 | 
						.probe		= pixcir_i2c_ts_probe,
 | 
				
			||||||
	.remove		= pixcir_i2c_ts_remove,
 | 
						.remove		= pixcir_i2c_ts_remove,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -264,7 +264,7 @@ static int s3c2410ts_probe(struct platform_device *pdev)
 | 
				
			||||||
		return -ENOENT;
 | 
							return -ENOENT;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	clk_enable(ts.clock);
 | 
						clk_prepare_enable(ts.clock);
 | 
				
			||||||
	dev_dbg(dev, "got and enabled clocks\n");
 | 
						dev_dbg(dev, "got and enabled clocks\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ts.irq_tc = ret = platform_get_irq(pdev, 0);
 | 
						ts.irq_tc = ret = platform_get_irq(pdev, 0);
 | 
				
			||||||
| 
						 | 
					@ -369,7 +369,7 @@ static int s3c2410ts_remove(struct platform_device *pdev)
 | 
				
			||||||
	free_irq(ts.irq_tc, ts.input);
 | 
						free_irq(ts.irq_tc, ts.input);
 | 
				
			||||||
	del_timer_sync(&touch_timer);
 | 
						del_timer_sync(&touch_timer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	clk_disable(ts.clock);
 | 
						clk_disable_unprepare(ts.clock);
 | 
				
			||||||
	clk_put(ts.clock);
 | 
						clk_put(ts.clock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	input_unregister_device(ts.input);
 | 
						input_unregister_device(ts.input);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -29,6 +29,8 @@
 | 
				
			||||||
#include <linux/sysfs.h>
 | 
					#include <linux/sysfs.h>
 | 
				
			||||||
#include <linux/input/mt.h>
 | 
					#include <linux/input/mt.h>
 | 
				
			||||||
#include <linux/platform_data/zforce_ts.h>
 | 
					#include <linux/platform_data/zforce_ts.h>
 | 
				
			||||||
 | 
					#include <linux/regulator/consumer.h>
 | 
				
			||||||
 | 
					#include <linux/delay.h>
 | 
				
			||||||
#include <linux/of.h>
 | 
					#include <linux/of.h>
 | 
				
			||||||
#include <linux/of_gpio.h>
 | 
					#include <linux/of_gpio.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -117,6 +119,8 @@ struct zforce_ts {
 | 
				
			||||||
	const struct zforce_ts_platdata *pdata;
 | 
						const struct zforce_ts_platdata *pdata;
 | 
				
			||||||
	char			phys[32];
 | 
						char			phys[32];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct regulator	*reg_vdd;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool			suspending;
 | 
						bool			suspending;
 | 
				
			||||||
	bool			suspended;
 | 
						bool			suspended;
 | 
				
			||||||
	bool			boot_complete;
 | 
						bool			boot_complete;
 | 
				
			||||||
| 
						 | 
					@ -690,6 +694,11 @@ static void zforce_reset(void *data)
 | 
				
			||||||
	struct zforce_ts *ts = data;
 | 
						struct zforce_ts *ts = data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	gpio_set_value(ts->pdata->gpio_rst, 0);
 | 
						gpio_set_value(ts->pdata->gpio_rst, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						udelay(10);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!IS_ERR(ts->reg_vdd))
 | 
				
			||||||
 | 
							regulator_disable(ts->reg_vdd);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct zforce_ts_platdata *zforce_parse_dt(struct device *dev)
 | 
					static struct zforce_ts_platdata *zforce_parse_dt(struct device *dev)
 | 
				
			||||||
| 
						 | 
					@ -765,10 +774,32 @@ static int zforce_probe(struct i2c_client *client,
 | 
				
			||||||
		return ret;
 | 
							return ret;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ts->reg_vdd = devm_regulator_get_optional(&client->dev, "vdd");
 | 
				
			||||||
 | 
						if (IS_ERR(ts->reg_vdd)) {
 | 
				
			||||||
 | 
							ret = PTR_ERR(ts->reg_vdd);
 | 
				
			||||||
 | 
							if (ret == -EPROBE_DEFER)
 | 
				
			||||||
 | 
								return ret;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							ret = regulator_enable(ts->reg_vdd);
 | 
				
			||||||
 | 
							if (ret)
 | 
				
			||||||
 | 
								return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/*
 | 
				
			||||||
 | 
							 * according to datasheet add 100us grace time after regular
 | 
				
			||||||
 | 
							 * regulator enable delay.
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							udelay(100);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ret = devm_add_action(&client->dev, zforce_reset, ts);
 | 
						ret = devm_add_action(&client->dev, zforce_reset, ts);
 | 
				
			||||||
	if (ret) {
 | 
						if (ret) {
 | 
				
			||||||
		dev_err(&client->dev, "failed to register reset action, %d\n",
 | 
							dev_err(&client->dev, "failed to register reset action, %d\n",
 | 
				
			||||||
			ret);
 | 
								ret);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* hereafter the regulator will be disabled by the action */
 | 
				
			||||||
 | 
							if (!IS_ERR(ts->reg_vdd))
 | 
				
			||||||
 | 
								regulator_disable(ts->reg_vdd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		return ret;
 | 
							return ret;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -97,8 +97,6 @@ static struct mxt_platform_data atmel_224s_tp_platform_data = {
 | 
				
			||||||
	.irqflags		= IRQF_TRIGGER_FALLING,
 | 
						.irqflags		= IRQF_TRIGGER_FALLING,
 | 
				
			||||||
	.t19_num_keys		= ARRAY_SIZE(mxt_t19_keys),
 | 
						.t19_num_keys		= ARRAY_SIZE(mxt_t19_keys),
 | 
				
			||||||
	.t19_keymap		= mxt_t19_keys,
 | 
						.t19_keymap		= mxt_t19_keys,
 | 
				
			||||||
	.config			= NULL,
 | 
					 | 
				
			||||||
	.config_length		= 0,
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct i2c_board_info atmel_224s_tp_device = {
 | 
					static struct i2c_board_info atmel_224s_tp_device = {
 | 
				
			||||||
| 
						 | 
					@ -109,8 +107,6 @@ static struct i2c_board_info atmel_224s_tp_device = {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct mxt_platform_data atmel_1664s_platform_data = {
 | 
					static struct mxt_platform_data atmel_1664s_platform_data = {
 | 
				
			||||||
	.irqflags		= IRQF_TRIGGER_FALLING,
 | 
						.irqflags		= IRQF_TRIGGER_FALLING,
 | 
				
			||||||
	.config			= NULL,
 | 
					 | 
				
			||||||
	.config_length		= 0,
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct i2c_board_info atmel_1664s_device = {
 | 
					static struct i2c_board_info atmel_1664s_device = {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -311,6 +311,11 @@ struct hid_item {
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
#define HID_GROUP_RMI				0x0100
 | 
					#define HID_GROUP_RMI				0x0100
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Vendor specific HID device groups
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define HID_GROUP_WACOM				0x0101
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * This is the global environment of the parser. This information is
 | 
					 * This is the global environment of the parser. This information is
 | 
				
			||||||
 * persistent for main-items. The global environment can be saved and
 | 
					 * persistent for main-items. The global environment can be saved and
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -17,9 +17,6 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* The platform data for the Atmel maXTouch touchscreen driver */
 | 
					/* The platform data for the Atmel maXTouch touchscreen driver */
 | 
				
			||||||
struct mxt_platform_data {
 | 
					struct mxt_platform_data {
 | 
				
			||||||
	const u8 *config;
 | 
					 | 
				
			||||||
	size_t config_length;
 | 
					 | 
				
			||||||
	u32 config_crc;
 | 
					 | 
				
			||||||
	unsigned long irqflags;
 | 
						unsigned long irqflags;
 | 
				
			||||||
	u8 t19_num_keys;
 | 
						u8 t19_num_keys;
 | 
				
			||||||
	const unsigned int *t19_keymap;
 | 
						const unsigned int *t19_keymap;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -43,10 +43,22 @@ enum pixcir_int_mode {
 | 
				
			||||||
#define PIXCIR_INT_ENABLE	(1UL << 3)
 | 
					#define PIXCIR_INT_ENABLE	(1UL << 3)
 | 
				
			||||||
#define PIXCIR_INT_POL_HIGH	(1UL << 2)
 | 
					#define PIXCIR_INT_POL_HIGH	(1UL << 2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * struct pixcir_irc_chip_data - chip related data
 | 
				
			||||||
 | 
					 * @max_fingers:	Max number of fingers reported simultaneously by h/w
 | 
				
			||||||
 | 
					 * @has_hw_ids:		Hardware supports finger tracking IDs
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					struct pixcir_i2c_chip_data {
 | 
				
			||||||
 | 
						u8 max_fingers;
 | 
				
			||||||
 | 
						bool has_hw_ids;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct pixcir_ts_platform_data {
 | 
					struct pixcir_ts_platform_data {
 | 
				
			||||||
	int x_max;
 | 
						int x_max;
 | 
				
			||||||
	int y_max;
 | 
						int y_max;
 | 
				
			||||||
	int gpio_attb;		/* GPIO connected to ATTB line */
 | 
						int gpio_attb;		/* GPIO connected to ATTB line */
 | 
				
			||||||
 | 
						struct pixcir_i2c_chip_data chip;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -76,5 +76,6 @@
 | 
				
			||||||
#define SERIO_HAMPSHIRE	0x3b
 | 
					#define SERIO_HAMPSHIRE	0x3b
 | 
				
			||||||
#define SERIO_PS2MULT	0x3c
 | 
					#define SERIO_PS2MULT	0x3c
 | 
				
			||||||
#define SERIO_TSC40	0x3d
 | 
					#define SERIO_TSC40	0x3d
 | 
				
			||||||
 | 
					#define SERIO_WACOM_IV	0x3e
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif /* _UAPI_SERIO_H */
 | 
					#endif /* _UAPI_SERIO_H */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -84,6 +84,15 @@ struct uinput_ff_erase {
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
#define UI_GET_SYSNAME(len)	_IOC(_IOC_READ, UINPUT_IOCTL_BASE, 300, len)
 | 
					#define UI_GET_SYSNAME(len)	_IOC(_IOC_READ, UINPUT_IOCTL_BASE, 300, len)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * UI_GET_VERSION - Return version of uinput protocol
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This writes uinput protocol version implemented by the kernel into
 | 
				
			||||||
 | 
					 * the integer pointed to by the ioctl argument. The protocol version
 | 
				
			||||||
 | 
					 * is hard-coded in the kernel and is independent of the uinput device.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define UI_GET_VERSION		_IOR(UINPUT_IOCTL_BASE, 301, unsigned int)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * To write a force-feedback-capable driver, the upload_effect
 | 
					 * To write a force-feedback-capable driver, the upload_effect
 | 
				
			||||||
 * and erase_effect callbacks in input_dev must be implemented.
 | 
					 * and erase_effect callbacks in input_dev must be implemented.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue