Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 15 Sep 2009 00:56:51 +0000 (17:56 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 15 Sep 2009 00:56:51 +0000 (17:56 -0700)
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input: (52 commits)
  Input: bcm5974 - silence uninitialized variables warnings
  Input: wistron_btns - add keymap for AOpen 1557
  Input: psmouse - use boolean type
  Input: i8042 - use platform_driver_probe
  Input: i8042 - use boolean type where it makes sense
  Input: i8042 - try disabling and re-enabling AUX port at close
  Input: pxa27x_keypad - allow modifying keymap from userspace
  Input: sunkbd - fix formatting
  Input: i8042 - bypass AUX IRQ delivery test on laptops
  Input: wacom_w8001 - simplify querying logic
  Input: atkbd - allow setting force-release bitmap via sysfs
  Input: w90p910_keypad - move a dereference below a NULL test
  Input: add twl4030_keypad driver
  Input: matrix-keypad - add function to build device keymap
  Input: tosakbd - fix cleaning up KEY_STROBEs after error
  Input: joydev - validate axis/button maps before clobbering current ones
  Input: xpad - add USB ID for the drumkit controller from Rock Band
  Input: w90p910_keypad - rename driver name to match platform
  Input: add new driver for Sentelic Finger Sensing Pad
  Input: psmouse - allow defining read-only attributes
  ...

77 files changed:
Documentation/input/sentelic.txt [new file with mode: 0644]
arch/arm/mach-pxa/include/mach/pxa27x_keypad.h
arch/arm/mach-w90x900/include/mach/w90p910_keypad.h [new file with mode: 0644]
arch/blackfin/include/asm/bfin_rotary.h [new file with mode: 0644]
drivers/base/platform.c
drivers/base/power/main.c
drivers/input/joydev.c
drivers/input/joystick/xpad.c
drivers/input/keyboard/Kconfig
drivers/input/keyboard/Makefile
drivers/input/keyboard/atkbd.c
drivers/input/keyboard/bf54x-keys.c
drivers/input/keyboard/gpio_keys.c
drivers/input/keyboard/hil_kbd.c
drivers/input/keyboard/lkkbd.c
drivers/input/keyboard/matrix_keypad.c
drivers/input/keyboard/pxa27x_keypad.c
drivers/input/keyboard/sh_keysc.c
drivers/input/keyboard/sunkbd.c
drivers/input/keyboard/tosakbd.c
drivers/input/keyboard/twl4030_keypad.c [new file with mode: 0644]
drivers/input/keyboard/w90p910_keypad.c [new file with mode: 0644]
drivers/input/misc/Kconfig
drivers/input/misc/Makefile
drivers/input/misc/bfin_rotary.c [new file with mode: 0644]
drivers/input/misc/cobalt_btns.c
drivers/input/misc/dm355evm_keys.c
drivers/input/misc/wistron_btns.c
drivers/input/mouse/Kconfig
drivers/input/mouse/Makefile
drivers/input/mouse/alps.c
drivers/input/mouse/alps.h
drivers/input/mouse/bcm5974.c
drivers/input/mouse/elantech.c
drivers/input/mouse/elantech.h
drivers/input/mouse/hgpk.c
drivers/input/mouse/hgpk.h
drivers/input/mouse/hil_ptr.c [deleted file]
drivers/input/mouse/lifebook.c
drivers/input/mouse/lifebook.h
drivers/input/mouse/logips2pp.c
drivers/input/mouse/logips2pp.h
drivers/input/mouse/psmouse-base.c
drivers/input/mouse/psmouse.h
drivers/input/mouse/sentelic.c [new file with mode: 0644]
drivers/input/mouse/sentelic.h [new file with mode: 0644]
drivers/input/mouse/synaptics.c
drivers/input/mouse/synaptics.h
drivers/input/mouse/touchkit_ps2.c
drivers/input/mouse/touchkit_ps2.h
drivers/input/mouse/trackpoint.c
drivers/input/mouse/trackpoint.h
drivers/input/mouse/vsxxxaa.c
drivers/input/serio/at32psif.c
drivers/input/serio/i8042-x86ia64io.h
drivers/input/serio/i8042.c
drivers/input/serio/libps2.c
drivers/input/serio/serio.c
drivers/input/touchscreen/Kconfig
drivers/input/touchscreen/atmel_tsadcc.c
drivers/input/touchscreen/eeti_ts.c
drivers/input/touchscreen/h3600_ts_input.c
drivers/input/touchscreen/mainstone-wm97xx.c
drivers/input/touchscreen/tsc2007.c
drivers/input/touchscreen/ucb1400_ts.c
drivers/input/touchscreen/usbtouchscreen.c
drivers/input/touchscreen/w90p910_ts.c
drivers/input/touchscreen/wacom_w8001.c
drivers/input/touchscreen/wm97xx-core.c
drivers/pci/pci-driver.c
include/linux/device.h
include/linux/i2c/twl4030.h
include/linux/input/eeti_ts.h [new file with mode: 0644]
include/linux/input/matrix_keypad.h
include/linux/libps2.h
include/linux/serio.h
include/linux/wm97xx.h

diff --git a/Documentation/input/sentelic.txt b/Documentation/input/sentelic.txt
new file mode 100644 (file)
index 0000000..f7160a2
--- /dev/null
@@ -0,0 +1,475 @@
+Copyright (C) 2002-2008 Sentelic Corporation.
+Last update: Oct-31-2008
+
+==============================================================================
+* Finger Sensing Pad Intellimouse Mode(scrolling wheel, 4th and 5th buttons)
+==============================================================================
+A) MSID 4: Scrolling wheel mode plus Forward page(4th button) and Backward
+   page (5th button)
+@1. Set sample rate to 200;
+@2. Set sample rate to 200;
+@3. Set sample rate to 80;
+@4. Issuing the "Get device ID" command (0xF2) and waits for the response;
+@5. FSP will respond 0x04.
+
+Packet 1
+   Bit 7 6 5 4 3 2 1 0       7 6 5 4 3 2 1 0      7 6 5 4 3 2 1 0      7 6 5 4 3 2 1 0
+BYTE  |---------------|BYTE |---------------|BYTE|---------------|BYTE|---------------|
+  1   |Y|X|y|x|1|M|R|L|  2  |X|X|X|X|X|X|X|X|  3 |Y|Y|Y|Y|Y|Y|Y|Y|  4 | | |B|F|W|W|W|W|
+      |---------------|     |---------------|    |---------------|    |---------------|
+
+Byte 1: Bit7 => Y overflow
+        Bit6 => X overflow
+        Bit5 => Y sign bit
+        Bit4 => X sign bit
+        Bit3 => 1
+        Bit2 => Middle Button, 1 is pressed, 0 is not pressed.
+        Bit1 => Right Button, 1 is pressed, 0 is not pressed.
+        Bit0 => Left Button, 1 is pressed, 0 is not pressed.
+Byte 2: X Movement(9-bit 2's complement integers)
+Byte 3: Y Movement(9-bit 2's complement integers)
+Byte 4: Bit3~Bit0 => the scrolling wheel's movement since the last data report.
+                     valid values, -8 ~ +7
+        Bit4 => 1 = 4th mouse button is pressed, Forward one page.
+                0 = 4th mouse button is not pressed.
+        Bit5 => 1 = 5th mouse button is pressed, Backward one page.
+                0 = 5th mouse button is not pressed.
+
+B) MSID 6: Horizontal and Vertical scrolling.
+@ Set bit 1 in register 0x40 to 1
+
+# FSP replaces scrolling wheel's movement as 4 bits to show horizontal and
+  vertical scrolling.
+
+Packet 1
+   Bit 7 6 5 4 3 2 1 0       7 6 5 4 3 2 1 0      7 6 5 4 3 2 1 0      7 6 5 4 3 2 1 0
+BYTE  |---------------|BYTE |---------------|BYTE|---------------|BYTE|---------------|
+  1   |Y|X|y|x|1|M|R|L|  2  |X|X|X|X|X|X|X|X|  3 |Y|Y|Y|Y|Y|Y|Y|Y|  4 | | |B|F|l|r|u|d|
+      |---------------|     |---------------|    |---------------|    |---------------|
+
+Byte 1: Bit7 => Y overflow
+        Bit6 => X overflow
+        Bit5 => Y sign bit
+        Bit4 => X sign bit
+        Bit3 => 1
+        Bit2 => Middle Button, 1 is pressed, 0 is not pressed.
+        Bit1 => Right Button, 1 is pressed, 0 is not pressed.
+        Bit0 => Left Button, 1 is pressed, 0 is not pressed.
+Byte 2: X Movement(9-bit 2's complement integers)
+Byte 3: Y Movement(9-bit 2's complement integers)
+Byte 4: Bit0 => the Vertical scrolling movement downward.
+       Bit1 => the Vertical scrolling movement upward.
+       Bit2 => the Vertical scrolling movement rightward.
+       Bit3 => the Vertical scrolling movement leftward.
+        Bit4 => 1 = 4th mouse button is pressed, Forward one page.
+                0 = 4th mouse button is not pressed.
+        Bit5 => 1 = 5th mouse button is pressed, Backward one page.
+                0 = 5th mouse button is not pressed.
+
+C) MSID 7:
+# FSP uses 2 packets(8 Bytes) data to represent Absolute Position
+  so we have PACKET NUMBER to identify packets.
+  If PACKET NUMBER is 0, the packet is Packet 1.
+  If PACKET NUMBER is 1, the packet is Packet 2.
+  Please count this number in program.
+
+# MSID6 special packet will be enable at the same time when enable MSID 7.
+
+==============================================================================
+* Absolute position for STL3886-G0.
+==============================================================================
+@ Set bit 2 or 3 in register 0x40 to 1
+@ Set bit 6 in register 0x40 to 1
+
+Packet 1 (ABSOLUTE POSITION)
+   Bit 7 6 5 4 3 2 1 0       7 6 5 4 3 2 1 0      7 6 5 4 3 2 1 0      7 6 5 4 3 2 1 0
+BYTE  |---------------|BYTE |---------------|BYTE|---------------|BYTE|---------------|
+  1   |0|1|V|1|1|M|R|L|  2  |X|X|X|X|X|X|X|X|  3 |Y|Y|Y|Y|Y|Y|Y|Y|  4 |r|l|d|u|X|X|Y|Y|
+      |---------------|     |---------------|    |---------------|    |---------------|
+
+Byte 1: Bit7~Bit6 => 00, Normal data packet
+                  => 01, Absolute coordination packet
+                  => 10, Notify packet
+        Bit5 => valid bit
+        Bit4 => 1
+        Bit3 => 1
+        Bit2 => Middle Button, 1 is pressed, 0 is not pressed.
+        Bit1 => Right Button, 1 is pressed, 0 is not pressed.
+        Bit0 => Left Button, 1 is pressed, 0 is not pressed.
+Byte 2: X coordinate (xpos[9:2])
+Byte 3: Y coordinate (ypos[9:2])
+Byte 4: Bit1~Bit0 => Y coordinate (xpos[1:0])
+        Bit3~Bit2 => X coordinate (ypos[1:0])
+        Bit4 => scroll up
+        Bit5 => scroll down
+        Bit6 => scroll left
+        Bit7 => scroll right
+
+Notify Packet for G0
+   Bit 7 6 5 4 3 2 1 0       7 6 5 4 3 2 1 0      7 6 5 4 3 2 1 0      7 6 5 4 3 2 1 0
+BYTE  |---------------|BYTE |---------------|BYTE|---------------|BYTE|---------------|
+  1   |1|0|0|1|1|M|R|L|  2  |C|C|C|C|C|C|C|C|  3 |M|M|M|M|M|M|M|M|  4 |0|0|0|0|0|0|0|0|
+      |---------------|     |---------------|    |---------------|    |---------------|
+
+Byte 1: Bit7~Bit6 => 00, Normal data packet
+                  => 01, Absolute coordination packet
+                  => 10, Notify packet
+        Bit5 => 0
+        Bit4 => 1
+        Bit3 => 1
+        Bit2 => Middle Button, 1 is pressed, 0 is not pressed.
+        Bit1 => Right Button, 1 is pressed, 0 is not pressed.
+        Bit0 => Left Button, 1 is pressed, 0 is not pressed.
+Byte 2: Message Type => 0x5A (Enable/Disable status packet)
+        Mode Type => 0xA5 (Normal/Icon mode status)
+Byte 3: Message Type => 0x00 (Disabled)
+                     => 0x01 (Enabled)
+        Mode Type    => 0x00 (Normal)
+                     => 0x01 (Icon)
+Byte 4: Bit7~Bit0 => Don't Care
+
+==============================================================================
+* Absolute position for STL3888-A0.
+==============================================================================
+Packet 1 (ABSOLUTE POSITION)
+   Bit 7 6 5 4 3 2 1 0       7 6 5 4 3 2 1 0      7 6 5 4 3 2 1 0      7 6 5 4 3 2 1 0
+BYTE  |---------------|BYTE |---------------|BYTE|---------------|BYTE|---------------|
+  1   |0|1|V|A|1|L|0|1|  2  |X|X|X|X|X|X|X|X|  3 |Y|Y|Y|Y|Y|Y|Y|Y|  4 |x|x|y|y|X|X|Y|Y|
+      |---------------|     |---------------|    |---------------|    |---------------|
+
+Byte 1: Bit7~Bit6 => 00, Normal data packet
+                  => 01, Absolute coordination packet
+                  => 10, Notify packet
+        Bit5 => Valid bit, 0 means that the coordinate is invalid or finger up.
+                When both fingers are up, the last two reports have zero valid
+                bit.
+        Bit4 => arc
+        Bit3 => 1
+        Bit2 => Left Button, 1 is pressed, 0 is released.
+        Bit1 => 0
+        Bit0 => 1
+Byte 2: X coordinate (xpos[9:2])
+Byte 3: Y coordinate (ypos[9:2])
+Byte 4: Bit1~Bit0 => Y coordinate (xpos[1:0])
+        Bit3~Bit2 => X coordinate (ypos[1:0])
+        Bit5~Bit4 => y1_g
+        Bit7~Bit6 => x1_g
+
+Packet 2 (ABSOLUTE POSITION)
+   Bit 7 6 5 4 3 2 1 0       7 6 5 4 3 2 1 0      7 6 5 4 3 2 1 0      7 6 5 4 3 2 1 0
+BYTE  |---------------|BYTE |---------------|BYTE|---------------|BYTE|---------------|
+  1   |0|1|V|A|1|R|1|0|  2  |X|X|X|X|X|X|X|X|  3 |Y|Y|Y|Y|Y|Y|Y|Y|  4 |x|x|y|y|X|X|Y|Y|
+      |---------------|     |---------------|    |---------------|    |---------------|
+
+Byte 1: Bit7~Bit6 => 00, Normal data packet
+                  => 01, Absolute coordinates packet
+                  => 10, Notify packet
+        Bit5 => Valid bit, 0 means that the coordinate is invalid or finger up.
+                When both fingers are up, the last two reports have zero valid
+                bit.
+        Bit4 => arc
+        Bit3 => 1
+        Bit2 => Right Button, 1 is pressed, 0 is released.
+        Bit1 => 1
+        Bit0 => 0
+Byte 2: X coordinate (xpos[9:2])
+Byte 3: Y coordinate (ypos[9:2])
+Byte 4: Bit1~Bit0 => Y coordinate (xpos[1:0])
+        Bit3~Bit2 => X coordinate (ypos[1:0])
+        Bit5~Bit4 => y2_g
+        Bit7~Bit6 => x2_g
+
+Notify Packet for STL3888-A0
+   Bit 7 6 5 4 3 2 1 0       7 6 5 4 3 2 1 0      7 6 5 4 3 2 1 0      7 6 5 4 3 2 1 0
+BYTE  |---------------|BYTE |---------------|BYTE|---------------|BYTE|---------------|
+  1   |1|0|1|P|1|M|R|L|  2  |C|C|C|C|C|C|C|C|  3 |0|0|F|F|0|0|0|i|  4 |r|l|d|u|0|0|0|0|
+      |---------------|     |---------------|    |---------------|    |---------------|
+
+Byte 1: Bit7~Bit6 => 00, Normal data packet
+                  => 01, Absolute coordination packet
+                  => 10, Notify packet
+        Bit5 => 1
+        Bit4 => when in absolute coordinates mode (valid when EN_PKT_GO is 1):
+                0: left button is generated by the on-pad command
+                1: left button is generated by the external button
+        Bit3 => 1
+        Bit2 => Middle Button, 1 is pressed, 0 is not pressed.
+        Bit1 => Right Button, 1 is pressed, 0 is not pressed.
+        Bit0 => Left Button, 1 is pressed, 0 is not pressed.
+Byte 2: Message Type => 0xB7 (Multi Finger, Multi Coordinate mode)
+Byte 3: Bit7~Bit6 => Don't care
+        Bit5~Bit4 => Number of fingers
+        Bit3~Bit1 => Reserved
+        Bit0 => 1: enter gesture mode; 0: leaving gesture mode
+Byte 4: Bit7 => scroll right button
+        Bit6 => scroll left button
+        Bit5 => scroll down button
+        Bit4 => scroll up button
+            * Note that if gesture and additional button (Bit4~Bit7)
+             happen at the same time, the button information will not
+             be sent.
+        Bit3~Bit0 => Reserved
+
+Sample sequence of Multi-finger, Multi-coordinate mode:
+
+       notify packet (valid bit == 1), abs pkt 1, abs pkt 2, abs pkt 1,
+       abs pkt 2, ..., notify packet(valid bit == 0)
+
+==============================================================================
+* FSP Enable/Disable packet
+==============================================================================
+   Bit 7 6 5 4 3 2 1 0       7 6 5 4 3 2 1 0      7 6 5 4 3 2 1 0      7 6 5 4 3 2 1 0
+BYTE  |---------------|BYTE |---------------|BYTE|---------------|BYTE|---------------|
+  1   |Y|X|0|0|1|M|R|L|  2  |0|1|0|1|1|0|1|E|  3 | | | | | | | | |  4 | | | | | | | | |
+      |---------------|     |---------------|    |---------------|    |---------------|
+
+FSP will send out enable/disable packet when FSP receive PS/2 enable/disable
+command. Host will receive the packet which Middle, Right, Left button will
+be set. The packet only use byte 0 and byte 1 as a pattern of original packet.
+Ignore the other bytes of the packet.
+
+Byte 1: Bit7 => 0, Y overflow
+        Bit6 => 0, X overflow
+       Bit5 => 0, Y sign bit
+        Bit4 => 0, X sign bit
+       Bit3 => 1
+       Bit2 => 1, Middle Button
+        Bit1 => 1, Right Button
+        Bit0 => 1, Left Button
+Byte 2: Bit7~1 => (0101101b)
+        Bit0 => 1 = Enable
+               0 = Disable
+Byte 3: Don't care
+Byte 4: Don't care (MOUSE ID 3, 4)
+Byte 5~8: Don't care (Absolute packet)
+
+==============================================================================
+* PS/2 Command Set
+==============================================================================
+
+FSP supports basic PS/2 commanding set and modes, refer to following URL for
+details about PS/2 commands:
+
+http://www.computer-engineering.org/index.php?title=PS/2_Mouse_Interface
+
+==============================================================================
+* Programming Sequence for Determining Packet Parsing Flow
+==============================================================================
+1. Identify FSP by reading device ID(0x00) and version(0x01) register
+
+2. Determine number of buttons by reading status2 (0x0b) register
+
+       buttons = reg[0x0b] & 0x30
+
+       if buttons == 0x30 or buttons == 0x20:
+               # two/four buttons
+               Refer to 'Finger Sensing Pad PS/2 Mouse Intellimouse'
+               section A for packet parsing detail(ignore byte 4, bit ~ 7)
+       elif buttons == 0x10:
+               # 6 buttons
+               Refer to 'Finger Sensing Pad PS/2 Mouse Intellimouse'
+               section B for packet parsing detail
+       elif buttons == 0x00:
+               # 6 buttons
+               Refer to 'Finger Sensing Pad PS/2 Mouse Intellimouse'
+               section A for packet parsing detail
+
+==============================================================================
+* Programming Sequence for Register Reading/Writing
+==============================================================================
+
+Register inversion requirement:
+
+  Following values needed to be inverted(the '~' operator in C) before being
+sent to FSP:
+
+       0xe9, 0xee, 0xf2 and 0xff.
+
+Register swapping requirement:
+
+  Following values needed to have their higher 4 bits and lower 4 bits being
+swapped before being sent to FSP:
+
+       10, 20, 40, 60, 80, 100 and 200.
+
+Register reading sequence:
+
+       1. send 0xf3 PS/2 command to FSP;
+
+       2. send 0x66 PS/2 command to FSP;
+
+       3. send 0x88 PS/2 command to FSP;
+
+       4. send 0xf3 PS/2 command to FSP;
+
+       5. if the register address being to read is not required to be
+       inverted(refer to the 'Register inversion requirement' section),
+       goto step 6
+
+       5a. send 0x68 PS/2 command to FSP;
+
+       5b. send the inverted register address to FSP and goto step 8;
+
+       6. if the register address being to read is not required to be
+       swapped(refer to the 'Register swapping requirement' section),
+       goto step 7
+
+       6a. send 0xcc PS/2 command to FSP;
+
+       6b. send the swapped register address to FSP and goto step 8;
+
+       7. send 0x66 PS/2 command to FSP;
+
+       7a. send the original register address to FSP and goto step 8;
+
+       8. send 0xe9(status request) PS/2 command to FSP;
+
+       9. the response read from FSP should be the requested register value.
+
+Register writing sequence:
+
+       1. send 0xf3 PS/2 command to FSP;
+
+       2. if the register address being to write is not required to be
+       inverted(refer to the 'Register inversion requirement' section),
+       goto step 3
+
+       2a. send 0x74 PS/2 command to FSP;
+
+       2b. send the inverted register address to FSP and goto step 5;
+
+       3. if the register address being to write is not required to be
+       swapped(refer to the 'Register swapping requirement' section),
+       goto step 4
+
+       3a. send 0x77 PS/2 command to FSP;
+
+       3b. send the swapped register address to FSP and goto step 5;
+
+       4. send 0x55 PS/2 command to FSP;
+
+       4a. send the register address to FSP and goto step 5;
+
+       5. send 0xf3 PS/2 command to FSP;
+
+       6. if the register value being to write is not required to be
+       inverted(refer to the 'Register inversion requirement' section),
+       goto step 7
+
+       6a. send 0x47 PS/2 command to FSP;
+
+       6b. send the inverted register value to FSP and goto step 9;
+
+       7. if the register value being to write is not required to be
+       swapped(refer to the 'Register swapping requirement' section),
+       goto step 8
+
+       7a. send 0x44 PS/2 command to FSP;
+
+       7b. send the swapped register value to FSP and goto step 9;
+
+       8. send 0x33 PS/2 command to FSP;
+
+       8a. send the register value to FSP;
+
+       9. the register writing sequence is completed.
+
+==============================================================================
+* Register Listing
+==============================================================================
+
+offset width           default r/w     name
+0x00   bit7~bit0       0x01    RO      device ID
+
+0x01   bit7~bit0       0xc0    RW      version ID
+
+0x02   bit7~bit0       0x01    RO      vendor ID
+
+0x03   bit7~bit0       0x01    RO      product ID
+
+0x04   bit3~bit0       0x01    RW      revision ID
+
+0x0b                           RO      test mode status 1
+       bit3            1       RO      0: rotate 180 degree, 1: no rotation
+
+       bit5~bit4               RO      number of buttons
+                       11 => 2, lbtn/rbtn
+                       10 => 4, lbtn/rbtn/scru/scrd
+                       01 => 6, lbtn/rbtn/scru/scrd/scrl/scrr
+                       00 => 6, lbtn/rbtn/scru/scrd/fbtn/bbtn
+
+0x0f                           RW      register file page control
+       bit0            0       RW      1 to enable page 1 register files
+
+0x10                           RW      system control 1
+       bit0            1       RW      Reserved, must be 1
+       bit1            0       RW      Reserved, must be 0
+       bit4            1       RW      Reserved, must be 0
+       bit5            0       RW      register clock gating enable
+                                       0: read only, 1: read/write enable
+       (Note that following registers does not require clock gating being
+       enabled prior to write: 05 06 07 08 09 0c 0f 10 11 12 16 17 18 23 2e
+       40 41 42 43.)
+
+0x31                           RW      on-pad command detection
+       bit7            0       RW      on-pad command left button down tag
+                                       enable
+                                       0: disable, 1: enable
+
+0x34                           RW      on-pad command control 5
+       bit4~bit0       0x05    RW      XLO in 0s/4/1, so 03h = 0010.1b = 2.5
+       (Note that position unit is in 0.5 scanline)
+
+       bit7            0       RW      on-pad tap zone enable
+                                       0: disable, 1: enable
+
+0x35                           RW      on-pad command control 6
+       bit4~bit0       0x1d    RW      XHI in 0s/4/1, so 19h = 1100.1b = 12.5
+       (Note that position unit is in 0.5 scanline)
+
+0x36                           RW      on-pad command control 7
+       bit4~bit0       0x04    RW      YLO in 0s/4/1, so 03h = 0010.1b = 2.5
+       (Note that position unit is in 0.5 scanline)
+
+0x37                           RW      on-pad command control 8
+       bit4~bit0       0x13    RW      YHI in 0s/4/1, so 11h = 1000.1b = 8.5
+       (Note that position unit is in 0.5 scanline)
+
+0x40                           RW      system control 5
+       bit1            0       RW      FSP Intellimouse mode enable
+                                       0: disable, 1: enable
+
+       bit2            0       RW      movement + abs. coordinate mode enable
+                                       0: disable, 1: enable
+       (Note that this function has the functionality of bit 1 even when
+       bit 1 is not set. However, the format is different from that of bit 1.
+       In addition, when bit 1 and bit 2 are set at the same time, bit 2 will
+       override bit 1.)
+
+       bit3            0       RW      abs. coordinate only mode enable
+                                       0: disable, 1: enable
+       (Note that this function has the functionality of bit 1 even when
+       bit 1 is not set. However, the format is different from that of bit 1.
+       In addition, when bit 1, bit 2 and bit 3 are set at the same time,
+       bit 3 will override bit 1 and 2.)
+
+       bit5            0       RW      auto switch enable
+                                       0: disable, 1: enable
+
+       bit6            0       RW      G0 abs. + notify packet format enable
+                                       0: disable, 1: enable
+       (Note that the absolute/relative coordinate output still depends on
+       bit 2 and 3.  That is, if any of those bit is 1, host will receive
+       absolute coordinates; otherwise, host only receives packets with
+       relative coordinate.)
+
+0x43                           RW      on-pad control
+       bit0            0       RW      on-pad control enable
+                                       0: disable, 1: enable
+       (Note that if this bit is cleared, bit 3/5 will be ineffective)
+
+       bit3            0       RW      on-pad fix vertical scrolling enable
+                                       0: disable, 1: enable
+
+       bit5            0       RW      on-pad fix horizontal scrolling enable
+                                       0: disable, 1: enable
index d5a48a96dea73471c3cf22e94d73b4f67131fd5b..7b4eadc6df3a8c7762329304b1cec2fefbc900ff 100644 (file)
@@ -2,9 +2,12 @@
 #define __ASM_ARCH_PXA27x_KEYPAD_H
 
 #include <linux/input.h>
+#include <linux/input/matrix_keypad.h>
 
 #define MAX_MATRIX_KEY_ROWS    (8)
 #define MAX_MATRIX_KEY_COLS    (8)
+#define MATRIX_ROW_SHIFT       (3)
+#define MAX_DIRECT_KEY_NUM     (8)
 
 /* pxa3xx keypad platform specific parameters
  *
@@ -33,7 +36,7 @@ struct pxa27x_keypad_platform_data {
 
        /* direct keys */
        int             direct_key_num;
-       unsigned int    direct_key_map[8];
+       unsigned int    direct_key_map[MAX_DIRECT_KEY_NUM];
 
        /* rotary encoders 0 */
        int             enable_rotary0;
@@ -51,8 +54,6 @@ struct pxa27x_keypad_platform_data {
        unsigned int    debounce_interval;
 };
 
-#define KEY(row, col, val)     (((row) << 28) | ((col) << 24) | (val))
-
 extern void pxa_set_keypad_info(struct pxa27x_keypad_platform_data *info);
 
 #endif /* __ASM_ARCH_PXA27x_KEYPAD_H */
diff --git a/arch/arm/mach-w90x900/include/mach/w90p910_keypad.h b/arch/arm/mach-w90x900/include/mach/w90p910_keypad.h
new file mode 100644 (file)
index 0000000..556778e
--- /dev/null
@@ -0,0 +1,15 @@
+#ifndef __ASM_ARCH_W90P910_KEYPAD_H
+#define __ASM_ARCH_W90P910_KEYPAD_H
+
+#include <linux/input/matrix_keypad.h>
+
+extern void mfp_set_groupi(struct device *dev);
+
+struct w90p910_keypad_platform_data {
+       const struct matrix_keymap_data *keymap_data;
+
+       unsigned int    prescale;
+       unsigned int    debounce;
+};
+
+#endif /* __ASM_ARCH_W90P910_KEYPAD_H */
diff --git a/arch/blackfin/include/asm/bfin_rotary.h b/arch/blackfin/include/asm/bfin_rotary.h
new file mode 100644 (file)
index 0000000..425ece6
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * board initialization should put one of these structures into platform_data
+ * and place the bfin-rotary onto platform_bus named "bfin-rotary".
+ */
+
+#ifndef _BFIN_ROTARY_H
+#define _BFIN_ROTARY_H
+
+/* mode bitmasks */
+#define ROT_QUAD_ENC   CNTMODE_QUADENC /* quadrature/grey code encoder mode */
+#define ROT_BIN_ENC    CNTMODE_BINENC  /* binary encoder mode */
+#define ROT_UD_CNT     CNTMODE_UDCNT   /* rotary counter mode */
+#define ROT_DIR_CNT    CNTMODE_DIRCNT  /* direction counter mode */
+
+#define ROT_DEBE       DEBE            /* Debounce Enable */
+
+#define ROT_CDGINV     CDGINV          /* CDG Pin Polarity Invert */
+#define ROT_CUDINV     CUDINV          /* CUD Pin Polarity Invert */
+#define ROT_CZMINV     CZMINV          /* CZM Pin Polarity Invert */
+
+struct bfin_rotary_platform_data {
+       /* set rotary UP KEY_### or BTN_### in case you prefer
+        * bfin-rotary to send EV_KEY otherwise set 0
+        */
+       unsigned int rotary_up_key;
+       /* set rotary DOWN KEY_### or BTN_### in case you prefer
+        * bfin-rotary to send EV_KEY otherwise set 0
+        */
+       unsigned int rotary_down_key;
+       /* set rotary BUTTON KEY_### or BTN_### */
+       unsigned int rotary_button_key;
+       /* set rotary Relative Axis REL_### in case you prefer
+        * bfin-rotary to send EV_REL otherwise set 0
+        */
+       unsigned int rotary_rel_code;
+       unsigned short debounce;        /* 0..17 */
+       unsigned short mode;
+};
+#endif
index 456594bd97bc5f13f9189854a73b84dfef157bd8..0b111e8e444f0c47ae62292a5d78e0ef16832a25 100644 (file)
@@ -922,7 +922,7 @@ static int platform_pm_restore_noirq(struct device *dev)
 
 #endif /* !CONFIG_HIBERNATION */
 
-static struct dev_pm_ops platform_dev_pm_ops = {
+static const struct dev_pm_ops platform_dev_pm_ops = {
        .prepare = platform_pm_prepare,
        .complete = platform_pm_complete,
        .suspend = platform_pm_suspend,
index 58a3e572f2c903ff81bfe75a51730257c49daf37..1b1a786b7deccb0b690138e97c737d19decf861a 100644 (file)
@@ -157,8 +157,9 @@ void device_pm_move_last(struct device *dev)
  *     @ops:   PM operations to choose from.
  *     @state: PM transition of the system being carried out.
  */
-static int pm_op(struct device *dev, struct dev_pm_ops *ops,
-                       pm_message_t state)
+static int pm_op(struct device *dev,
+                const struct dev_pm_ops *ops,
+                pm_message_t state)
 {
        int error = 0;
 
@@ -220,7 +221,8 @@ static int pm_op(struct device *dev, struct dev_pm_ops *ops,
  *     The operation is executed with interrupts disabled by the only remaining
  *     functional CPU in the system.
  */
-static int pm_noirq_op(struct device *dev, struct dev_pm_ops *ops,
+static int pm_noirq_op(struct device *dev,
+                       const struct dev_pm_ops *ops,
                        pm_message_t state)
 {
        int error = 0;
index 9a1d55b74d7a0b79296ee909a11011140f71d4a3..901b2525993e54f77c219cac9b1d55e3431219e5 100644 (file)
@@ -452,6 +452,76 @@ static unsigned int joydev_poll(struct file *file, poll_table *wait)
                (joydev->exist ?  0 : (POLLHUP | POLLERR));
 }
 
+static int joydev_handle_JSIOCSAXMAP(struct joydev *joydev,
+                                    void __user *argp, size_t len)
+{
+       __u8 *abspam;
+       int i;
+       int retval = 0;
+
+       len = min(len, sizeof(joydev->abspam));
+
+       /* Validate the map. */
+       abspam = kmalloc(len, GFP_KERNEL);
+       if (!abspam)
+               return -ENOMEM;
+
+       if (copy_from_user(abspam, argp, len)) {
+               retval = -EFAULT;
+               goto out;
+       }
+
+       for (i = 0; i < joydev->nabs; i++) {
+               if (abspam[i] > ABS_MAX) {
+                       retval = -EINVAL;
+                       goto out;
+               }
+       }
+
+       memcpy(joydev->abspam, abspam, len);
+
+ out:
+       kfree(abspam);
+       return retval;
+}
+
+static int joydev_handle_JSIOCSBTNMAP(struct joydev *joydev,
+                                     void __user *argp, size_t len)
+{
+       __u16 *keypam;
+       int i;
+       int retval = 0;
+
+       len = min(len, sizeof(joydev->keypam));
+
+       /* Validate the map. */
+       keypam = kmalloc(len, GFP_KERNEL);
+       if (!keypam)
+               return -ENOMEM;
+
+       if (copy_from_user(keypam, argp, len)) {
+               retval = -EFAULT;
+               goto out;
+       }
+
+       for (i = 0; i < joydev->nkey; i++) {
+               if (keypam[i] > KEY_MAX || keypam[i] < BTN_MISC) {
+                       retval = -EINVAL;
+                       goto out;
+               }
+       }
+
+       memcpy(joydev->keypam, keypam, len);
+
+       for (i = 0; i < joydev->nkey; i++)
+               joydev->keymap[keypam[i] - BTN_MISC] = i;
+
+ out:
+       kfree(keypam);
+       return retval;
+}
+
+
 static int joydev_ioctl_common(struct joydev *joydev,
                                unsigned int cmd, void __user *argp)
 {
@@ -512,46 +582,18 @@ static int joydev_ioctl_common(struct joydev *joydev,
        switch (cmd & ~IOCSIZE_MASK) {
 
        case (JSIOCSAXMAP & ~IOCSIZE_MASK):
-               len = min_t(size_t, _IOC_SIZE(cmd), sizeof(joydev->abspam));
-               /*
-                * FIXME: we should not copy into our axis map before
-                * validating the data.
-                */
-               if (copy_from_user(joydev->abspam, argp, len))
-                       return -EFAULT;
-
-               for (i = 0; i < joydev->nabs; i++) {
-                       if (joydev->abspam[i] > ABS_MAX)
-                               return -EINVAL;
-                       joydev->absmap[joydev->abspam[i]] = i;
-               }
-               return 0;
+               return joydev_handle_JSIOCSAXMAP(joydev, argp, _IOC_SIZE(cmd));
 
        case (JSIOCGAXMAP & ~IOCSIZE_MASK):
                len = min_t(size_t, _IOC_SIZE(cmd), sizeof(joydev->abspam));
-               return copy_to_user(argp, joydev->abspam, len) ? -EFAULT : 0;
+               return copy_to_user(argp, joydev->abspam, len) ? -EFAULT : len;
 
        case (JSIOCSBTNMAP & ~IOCSIZE_MASK):
-               len = min_t(size_t, _IOC_SIZE(cmd), sizeof(joydev->keypam));
-               /*
-                * FIXME: we should not copy into our keymap before
-                * validating the data.
-                */
-               if (copy_from_user(joydev->keypam, argp, len))
-                       return -EFAULT;
-
-               for (i = 0; i < joydev->nkey; i++) {
-                       if (joydev->keypam[i] > KEY_MAX ||
-                           joydev->keypam[i] < BTN_MISC)
-                               return -EINVAL;
-                       joydev->keymap[joydev->keypam[i] - BTN_MISC] = i;
-               }
-
-               return 0;
+               return joydev_handle_JSIOCSBTNMAP(joydev, argp, _IOC_SIZE(cmd));
 
        case (JSIOCGBTNMAP & ~IOCSIZE_MASK):
                len = min_t(size_t, _IOC_SIZE(cmd), sizeof(joydev->keypam));
-               return copy_to_user(argp, joydev->keypam, len) ? -EFAULT : 0;
+               return copy_to_user(argp, joydev->keypam, len) ? -EFAULT : len;
 
        case JSIOCGNAME(0):
                name = dev->name;
index f155ad8cdae7e16b8240b20c95c983be24536c41..2388cf578a62d4f84b807efd8b3a143077f2f20a 100644 (file)
@@ -144,6 +144,7 @@ static const struct xpad_device {
        { 0x1430, 0x4748, "RedOctane Guitar Hero X-plorer", MAP_DPAD_TO_AXES, XTYPE_XBOX360 },
        { 0x1430, 0x8888, "TX6500+ Dance Pad (first generation)", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },
        { 0x045e, 0x028e, "Microsoft X-Box 360 pad", MAP_DPAD_TO_AXES, XTYPE_XBOX360 },
+       { 0x1bad, 0x0003, "Harmonix Rock Band Drumkit", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 },
        { 0xffff, 0xffff, "Chinese-made Xbox Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
        { 0x0000, 0x0000, "Generic X-Box pad", MAP_DPAD_UNKNOWN, XTYPE_UNKNOWN }
 };
@@ -208,6 +209,7 @@ static struct usb_device_id xpad_table [] = {
        XPAD_XBOX360_VENDOR(0x0738),            /* Mad Catz X-Box 360 controllers */
        XPAD_XBOX360_VENDOR(0x0e6f),            /* 0x0e6f X-Box 360 controllers */
        XPAD_XBOX360_VENDOR(0x1430),            /* RedOctane X-Box 360 controllers */
+       XPAD_XBOX360_VENDOR(0x1bad),            /* Rock Band Drums */
        { }
 };
 
index a6b989a9dc07eee021d90e1d6f4ae902da547056..3525c19be4286e14f71568656142ff7215fc8dbc 100644 (file)
@@ -187,7 +187,7 @@ config KEYBOARD_HIL_OLD
          submenu.
 
 config KEYBOARD_HIL
-       tristate "HP HIL keyboard support"
+       tristate "HP HIL keyboard/pointer support"
        depends on GSC || HP300
        default y
        select HP_SDC
@@ -196,7 +196,8 @@ config KEYBOARD_HIL
        help
          The "Human Interface Loop" is a older, 8-channel USB-like
          controller used in several Hewlett Packard models.
-         This driver implements support for HIL-keyboards attached
+         This driver implements support for HIL-keyboards and pointing
+         devices (mice, tablets, touchscreens) attached
          to your machine, so normally you should say Y here.
 
 config KEYBOARD_HP6XX
@@ -329,6 +330,17 @@ config KEYBOARD_OMAP
          To compile this driver as a module, choose M here: the
          module will be called omap-keypad.
 
+config KEYBOARD_TWL4030
+       tristate "TI TWL4030/TWL5030/TPS659x0 keypad support"
+       depends on TWL4030_CORE
+       help
+         Say Y here if your board use the keypad controller on
+         TWL4030 family chips.  It's safe to say enable this
+         even on boards that don't use the keypad controller.
+
+         To compile this driver as a module, choose M here: the
+         module will be called twl4030_keypad.
+
 config KEYBOARD_TOSA
        tristate "Tosa keyboard"
        depends on MACH_TOSA
@@ -361,4 +373,14 @@ config KEYBOARD_XTKBD
          To compile this driver as a module, choose M here: the
          module will be called xtkbd.
 
+config KEYBOARD_W90P910
+       tristate "W90P910 Matrix Keypad support"
+       depends on ARCH_W90X900
+       help
+         Say Y here to enable the matrix keypad on evaluation board
+         based on W90P910.
+
+         To compile this driver as a module, choose M here: the
+         module will be called w90p910_keypad.
+
 endif
index b5b5eae9724fa5f49b651bcd987ebeb5d0707c18..8a7a22b302666618c4472aa11b8d91b395e39bd6 100644 (file)
@@ -30,4 +30,6 @@ obj-$(CONFIG_KEYBOARD_SPITZ)          += spitzkbd.o
 obj-$(CONFIG_KEYBOARD_STOWAWAY)                += stowaway.o
 obj-$(CONFIG_KEYBOARD_SUNKBD)          += sunkbd.o
 obj-$(CONFIG_KEYBOARD_TOSA)            += tosakbd.o
+obj-$(CONFIG_KEYBOARD_TWL4030)         += twl4030_keypad.o
 obj-$(CONFIG_KEYBOARD_XTKBD)           += xtkbd.o
+obj-$(CONFIG_KEYBOARD_W90P910)         += w90p910_keypad.o
index 6c6a09b1c0fed5f116ccddd4ab39de971c08e5a4..c9523e48c6ad4240c125e0c168ee77ba1010433c 100644 (file)
@@ -68,7 +68,9 @@ MODULE_PARM_DESC(extra, "Enable extra LEDs and keys on IBM RapidAcces, EzKey and
  * are loadable via a userland utility.
  */
 
-static const unsigned short atkbd_set2_keycode[512] = {
+#define ATKBD_KEYMAP_SIZE      512
+
+static const unsigned short atkbd_set2_keycode[ATKBD_KEYMAP_SIZE] = {
 
 #ifdef CONFIG_KEYBOARD_ATKBD_HP_KEYCODES
 
@@ -99,7 +101,7 @@ static const unsigned short atkbd_set2_keycode[512] = {
 #endif
 };
 
-static const unsigned short atkbd_set3_keycode[512] = {
+static const unsigned short atkbd_set3_keycode[ATKBD_KEYMAP_SIZE] = {
 
          0,  0,  0,  0,  0,  0,  0, 59,  1,138,128,129,130, 15, 41, 60,
        131, 29, 42, 86, 58, 16,  2, 61,133, 56, 44, 31, 30, 17,  3, 62,
@@ -200,8 +202,8 @@ struct atkbd {
        char phys[32];
 
        unsigned short id;
-       unsigned short keycode[512];
-       DECLARE_BITMAP(force_release_mask, 512);
+       unsigned short keycode[ATKBD_KEYMAP_SIZE];
+       DECLARE_BITMAP(force_release_mask, ATKBD_KEYMAP_SIZE);
        unsigned char set;
        unsigned char translated;
        unsigned char extra;
@@ -253,6 +255,7 @@ static struct device_attribute atkbd_attr_##_name =                         \
        __ATTR(_name, S_IWUSR | S_IRUGO, atkbd_do_show_##_name, atkbd_do_set_##_name);
 
 ATKBD_DEFINE_ATTR(extra);
+ATKBD_DEFINE_ATTR(force_release);
 ATKBD_DEFINE_ATTR(scroll);
 ATKBD_DEFINE_ATTR(set);
 ATKBD_DEFINE_ATTR(softrepeat);
@@ -272,6 +275,7 @@ ATKBD_DEFINE_RO_ATTR(err_count);
 
 static struct attribute *atkbd_attributes[] = {
        &atkbd_attr_extra.attr,
+       &atkbd_attr_force_release.attr,
        &atkbd_attr_scroll.attr,
        &atkbd_attr_set.attr,
        &atkbd_attr_softrepeat.attr,
@@ -934,7 +938,7 @@ static void atkbd_set_keycode_table(struct atkbd *atkbd)
        int i, j;
 
        memset(atkbd->keycode, 0, sizeof(atkbd->keycode));
-       bitmap_zero(atkbd->force_release_mask, 512);
+       bitmap_zero(atkbd->force_release_mask, ATKBD_KEYMAP_SIZE);
 
        if (atkbd->translated) {
                for (i = 0; i < 128; i++) {
@@ -1041,7 +1045,7 @@ static void atkbd_set_device_attrs(struct atkbd *atkbd)
        input_dev->keycodesize = sizeof(unsigned short);
        input_dev->keycodemax = ARRAY_SIZE(atkbd_set2_keycode);
 
-       for (i = 0; i < 512; i++)
+       for (i = 0; i < ATKBD_KEYMAP_SIZE; i++)
                if (atkbd->keycode[i] && atkbd->keycode[i] < ATKBD_SPECIAL)
                        __set_bit(atkbd->keycode[i], input_dev->keybit);
 }
@@ -1309,6 +1313,33 @@ static ssize_t atkbd_set_extra(struct atkbd *atkbd, const char *buf, size_t coun
        return count;
 }
 
+static ssize_t atkbd_show_force_release(struct atkbd *atkbd, char *buf)
+{
+       size_t len = bitmap_scnlistprintf(buf, PAGE_SIZE - 2,
+                       atkbd->force_release_mask, ATKBD_KEYMAP_SIZE);
+
+       buf[len++] = '\n';
+       buf[len] = '\0';
+
+       return len;
+}
+
+static ssize_t atkbd_set_force_release(struct atkbd *atkbd,
+                                       const char *buf, size_t count)
+{
+       /* 64 bytes on stack should be acceptable */
+       DECLARE_BITMAP(new_mask, ATKBD_KEYMAP_SIZE);
+       int err;
+
+       err = bitmap_parselist(buf, new_mask, ATKBD_KEYMAP_SIZE);
+       if (err)
+               return err;
+
+       memcpy(atkbd->force_release_mask, new_mask, sizeof(atkbd->force_release_mask));
+       return count;
+}
+
+
 static ssize_t atkbd_show_scroll(struct atkbd *atkbd, char *buf)
 {
        return sprintf(buf, "%d\n", atkbd->scroll ? 1 : 0);
index d427f322e2079635ab8dbfca89e2b17e5af78b06..fe376a27fe5779dfdd403fb42733978983451e48 100644 (file)
@@ -184,14 +184,13 @@ static int __devinit bfin_kpad_probe(struct platform_device *pdev)
        int i, error;
 
        if (!pdata->rows || !pdata->cols || !pdata->keymap) {
-               printk(KERN_ERR DRV_NAME
-                       ": No rows, cols or keymap from pdata\n");
+               dev_err(&pdev->dev, "no rows, cols or keymap from pdata\n");
                return -EINVAL;
        }
 
        if (!pdata->keymapsize ||
            pdata->keymapsize > (pdata->rows * pdata->cols)) {
-               printk(KERN_ERR DRV_NAME ": Invalid keymapsize\n");
+               dev_err(&pdev->dev, "invalid keymapsize\n");
                return -EINVAL;
        }
 
@@ -211,8 +210,8 @@ static int __devinit bfin_kpad_probe(struct platform_device *pdev)
 
        if (!pdata->debounce_time || pdata->debounce_time > MAX_MULT ||
            !pdata->coldrive_time || pdata->coldrive_time > MAX_MULT) {
-               printk(KERN_WARNING DRV_NAME
-                       ": Invalid Debounce/Columndrive Time in platform data\n");
+               dev_warn(&pdev->dev,
+                       "invalid platform debounce/columndrive time\n");
                bfin_write_KPAD_MSEL(0xFF0);    /* Default MSEL */
        } else {
                bfin_write_KPAD_MSEL(
@@ -231,16 +230,14 @@ static int __devinit bfin_kpad_probe(struct platform_device *pdev)
 
        if (peripheral_request_list((u16 *)&per_rows[MAX_RC - pdata->rows],
                                    DRV_NAME)) {
-               printk(KERN_ERR DRV_NAME
-                       ": Requesting Peripherals failed\n");
+               dev_err(&pdev->dev, "requesting peripherals failed\n");
                error = -EFAULT;
                goto out0;
        }
 
        if (peripheral_request_list((u16 *)&per_cols[MAX_RC - pdata->cols],
                                    DRV_NAME)) {
-               printk(KERN_ERR DRV_NAME
-                       ": Requesting Peripherals failed\n");
+               dev_err(&pdev->dev, "requesting peripherals failed\n");
                error = -EFAULT;
                goto out1;
        }
@@ -254,9 +251,8 @@ static int __devinit bfin_kpad_probe(struct platform_device *pdev)
        error = request_irq(bf54x_kpad->irq, bfin_kpad_isr,
                                0, DRV_NAME, pdev);
        if (error) {
-               printk(KERN_ERR DRV_NAME
-                       ": unable to claim irq %d; error %d\n",
-                       bf54x_kpad->irq, error);
+               dev_err(&pdev->dev, "unable to claim irq %d\n",
+                       bf54x_kpad->irq);
                goto out2;
        }
 
@@ -297,8 +293,7 @@ static int __devinit bfin_kpad_probe(struct platform_device *pdev)
 
        error = input_register_device(input);
        if (error) {
-               printk(KERN_ERR DRV_NAME
-                       ": Unable to register input device (%d)\n", error);
+               dev_err(&pdev->dev, "unable to register input device\n");
                goto out4;
        }
 
@@ -316,9 +311,6 @@ static int __devinit bfin_kpad_probe(struct platform_device *pdev)
 
        device_init_wakeup(&pdev->dev, 1);
 
-       printk(KERN_ERR DRV_NAME
-               ": Blackfin BF54x Keypad registered IRQ %d\n", bf54x_kpad->irq);
-
        return 0;
 
 out4:
index efed0c9e242ed1880f618aa73c67ae0a1eab470b..a88aff3816a0440558ce34ee799fbbc003d0731d 100644 (file)
@@ -216,8 +216,9 @@ static int __devexit gpio_keys_remove(struct platform_device *pdev)
 
 
 #ifdef CONFIG_PM
-static int gpio_keys_suspend(struct platform_device *pdev, pm_message_t state)
+static int gpio_keys_suspend(struct device *dev)
 {
+       struct platform_device *pdev = to_platform_device(dev);
        struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
        int i;
 
@@ -234,8 +235,9 @@ static int gpio_keys_suspend(struct platform_device *pdev, pm_message_t state)
        return 0;
 }
 
-static int gpio_keys_resume(struct platform_device *pdev)
+static int gpio_keys_resume(struct device *dev)
 {
+       struct platform_device *pdev = to_platform_device(dev);
        struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
        int i;
 
@@ -251,19 +253,22 @@ static int gpio_keys_resume(struct platform_device *pdev)
 
        return 0;
 }
-#else
-#define gpio_keys_suspend      NULL
-#define gpio_keys_resume       NULL
+
+static const struct dev_pm_ops gpio_keys_pm_ops = {
+       .suspend        = gpio_keys_suspend,
+       .resume         = gpio_keys_resume,
+};
 #endif
 
 static struct platform_driver gpio_keys_device_driver = {
        .probe          = gpio_keys_probe,
        .remove         = __devexit_p(gpio_keys_remove),
-       .suspend        = gpio_keys_suspend,
-       .resume         = gpio_keys_resume,
        .driver         = {
                .name   = "gpio-keys",
                .owner  = THIS_MODULE,
+#ifdef CONFIG_PM
+               .pm     = &gpio_keys_pm_ops,
+#endif
        }
 };
 
index 6f356705ee3bb9025937742cc558627ea0e60f03..c83f4b2ec7d3546e5229cb148b4a087265b05c16 100644 (file)
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/init.h>
-#include <linux/semaphore.h>
+#include <linux/completion.h>
 #include <linux/slab.h>
 #include <linux/pci_ids.h>
 
-#define PREFIX "HIL KEYB: "
-#define HIL_GENERIC_NAME "HIL keyboard"
+#define PREFIX "HIL: "
 
 MODULE_AUTHOR("Brian S. Julin <bri@calyx.com>");
-MODULE_DESCRIPTION(HIL_GENERIC_NAME " driver");
+MODULE_DESCRIPTION("HIL keyboard/mouse driver");
 MODULE_LICENSE("Dual BSD/GPL");
-MODULE_ALIAS("serio:ty03pr25id00ex*");
+MODULE_ALIAS("serio:ty03pr25id00ex*"); /* HIL keyboard */
+MODULE_ALIAS("serio:ty03pr25id0Fex*"); /* HIL mouse */
 
-#define HIL_KBD_MAX_LENGTH 16
+#define HIL_PACKET_MAX_LENGTH 16
 
 #define HIL_KBD_SET1_UPBIT 0x01
 #define HIL_KBD_SET1_SHIFT 1
@@ -67,308 +67,497 @@ static unsigned int hil_kbd_set3[HIL_KEYCODES_SET3_TBLSIZE] __read_mostly =
 
 static const char hil_language[][16] = { HIL_LOCALE_MAP };
 
-struct hil_kbd {
+struct hil_dev {
        struct input_dev *dev;
        struct serio *serio;
 
        /* Input buffer and index for packets from HIL bus. */
-       hil_packet data[HIL_KBD_MAX_LENGTH];
+       hil_packet data[HIL_PACKET_MAX_LENGTH];
        int idx4; /* four counts per packet */
 
        /* Raw device info records from HIL bus, see hil.h for fields. */
-       char    idd[HIL_KBD_MAX_LENGTH];        /* DID byte and IDD record */
-       char    rsc[HIL_KBD_MAX_LENGTH];        /* RSC record */
-       char    exd[HIL_KBD_MAX_LENGTH];        /* EXD record */
-       char    rnm[HIL_KBD_MAX_LENGTH + 1];    /* RNM record + NULL term. */
+       char    idd[HIL_PACKET_MAX_LENGTH];     /* DID byte and IDD record */
+       char    rsc[HIL_PACKET_MAX_LENGTH];     /* RSC record */
+       char    exd[HIL_PACKET_MAX_LENGTH];     /* EXD record */
+       char    rnm[HIL_PACKET_MAX_LENGTH + 1]; /* RNM record + NULL term. */
 
-       /* Something to sleep around with. */
-       struct semaphore sem;
+       struct completion cmd_done;
+
+       bool is_pointer;
+       /* Extra device details needed for pointing devices. */
+       unsigned int nbtn, naxes;
+       unsigned int btnmap[7];
 };
 
-/* Process a complete packet after transfer from the HIL */
-static void hil_kbd_process_record(struct hil_kbd *kbd)
+static bool hil_dev_is_command_response(hil_packet p)
 {
-       struct input_dev *dev = kbd->dev;
-       hil_packet *data = kbd->data;
-       hil_packet p;
-       int idx, i, cnt;
+       if ((p & ~HIL_CMDCT_POL) == (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_POL))
+               return false;
 
-       idx = kbd->idx4/4;
-       p = data[idx - 1];
+       if ((p & ~HIL_CMDCT_RPL) == (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_RPL))
+               return false;
 
-       if ((p & ~HIL_CMDCT_POL) ==
-           (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_POL))
-               goto report;
-       if ((p & ~HIL_CMDCT_RPL) ==
-           (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_RPL))
-               goto report;
+       return true;
+}
+
+static void hil_dev_handle_command_response(struct hil_dev *dev)
+{
+       hil_packet p;
+       char *buf;
+       int i, idx;
+
+       idx = dev->idx4 / 4;
+       p = dev->data[idx - 1];
 
-       /* Not a poll response.  See if we are loading config records. */
        switch (p & HIL_PKT_DATA_MASK) {
        case HIL_CMD_IDD:
-               for (i = 0; i < idx; i++)
-                       kbd->idd[i] = kbd->data[i] & HIL_PKT_DATA_MASK;
-               for (; i < HIL_KBD_MAX_LENGTH; i++)
-                       kbd->idd[i] = 0;
+               buf = dev->idd;
                break;
 
        case HIL_CMD_RSC:
-               for (i = 0; i < idx; i++)
-                       kbd->rsc[i] = kbd->data[i] & HIL_PKT_DATA_MASK;
-               for (; i < HIL_KBD_MAX_LENGTH; i++)
-                       kbd->rsc[i] = 0;
+               buf = dev->rsc;
                break;
 
        case HIL_CMD_EXD:
-               for (i = 0; i < idx; i++)
-                       kbd->exd[i] = kbd->data[i] & HIL_PKT_DATA_MASK;
-               for (; i < HIL_KBD_MAX_LENGTH; i++)
-                       kbd->exd[i] = 0;
+               buf = dev->exd;
                break;
 
        case HIL_CMD_RNM:
-               for (i = 0; i < idx; i++)
-                       kbd->rnm[i] = kbd->data[i] & HIL_PKT_DATA_MASK;
-               for (; i < HIL_KBD_MAX_LENGTH + 1; i++)
-                       kbd->rnm[i] = '\0';
+               dev->rnm[HIL_PACKET_MAX_LENGTH] = 0;
+               buf = dev->rnm;
                break;
 
        default:
                /* These occur when device isn't present */
-               if (p == (HIL_ERR_INT | HIL_PKT_CMD))
-                       break;
-               /* Anything else we'd like to know about. */
-               printk(KERN_WARNING PREFIX "Device sent unknown record %x\n", p);
-               break;
+               if (p != (HIL_ERR_INT | HIL_PKT_CMD)) {
+                       /* Anything else we'd like to know about. */
+                       printk(KERN_WARNING PREFIX "Device sent unknown record %x\n", p);
+               }
+               goto out;
        }
-       goto out;
 
- report:
-       cnt = 1;
+       for (i = 0; i < idx; i++)
+               buf[i] = dev->data[i] & HIL_PKT_DATA_MASK;
+       for (; i < HIL_PACKET_MAX_LENGTH; i++)
+               buf[i] = 0;
+ out:
+       complete(&dev->cmd_done);
+}
+
+static void hil_dev_handle_kbd_events(struct hil_dev *kbd)
+{
+       struct input_dev *dev = kbd->dev;
+       int idx = kbd->idx4 / 4;
+       int i;
+
        switch (kbd->data[0] & HIL_POL_CHARTYPE_MASK) {
        case HIL_POL_CHARTYPE_NONE:
-               break;
+               return;
 
        case HIL_POL_CHARTYPE_ASCII:
-               while (cnt < idx - 1)
-                       input_report_key(dev, kbd->data[cnt++] & 0x7f, 1);
+               for (i = 1; i < idx - 1; i++)
+                       input_report_key(dev, kbd->data[i] & 0x7f, 1);
                break;
 
        case HIL_POL_CHARTYPE_RSVD1:
        case HIL_POL_CHARTYPE_RSVD2:
        case HIL_POL_CHARTYPE_BINARY:
-               while (cnt < idx - 1)
-                       input_report_key(dev, kbd->data[cnt++], 1);
+               for (i = 1; i < idx - 1; i++)
+                       input_report_key(dev, kbd->data[i], 1);
                break;
 
        case HIL_POL_CHARTYPE_SET1:
-               while (cnt < idx - 1) {
-                       unsigned int key;
-                       int up;
-                       key = kbd->data[cnt++];
-                       up = key & HIL_KBD_SET1_UPBIT;
+               for (i = 1; i < idx - 1; i++) {
+                       unsigned int key = kbd->data[i];
+                       int up = key & HIL_KBD_SET1_UPBIT;
+
                        key &= (~HIL_KBD_SET1_UPBIT & 0xff);
                        key = hil_kbd_set1[key >> HIL_KBD_SET1_SHIFT];
-                       if (key != KEY_RESERVED)
-                               input_report_key(dev, key, !up);
+                       input_report_key(dev, key, !up);
                }
                break;
 
        case HIL_POL_CHARTYPE_SET2:
-               while (cnt < idx - 1) {
-                       unsigned int key;
-                       int up;
-                       key = kbd->data[cnt++];
-                       up = key & HIL_KBD_SET2_UPBIT;
+               for (i = 1; i < idx - 1; i++) {
+                       unsigned int key = kbd->data[i];
+                       int up = key & HIL_KBD_SET2_UPBIT;
+
                        key &= (~HIL_KBD_SET1_UPBIT & 0xff);
                        key = key >> HIL_KBD_SET2_SHIFT;
-                       if (key != KEY_RESERVED)
-                               input_report_key(dev, key, !up);
+                       input_report_key(dev, key, !up);
                }
                break;
 
        case HIL_POL_CHARTYPE_SET3:
-               while (cnt < idx - 1) {
-                       unsigned int key;
-                       int up;
-                       key = kbd->data[cnt++];
-                       up = key & HIL_KBD_SET3_UPBIT;
+               for (i = 1; i < idx - 1; i++) {
+                       unsigned int key = kbd->data[i];
+                       int up = key & HIL_KBD_SET3_UPBIT;
+
                        key &= (~HIL_KBD_SET1_UPBIT & 0xff);
                        key = hil_kbd_set3[key >> HIL_KBD_SET3_SHIFT];
-                       if (key != KEY_RESERVED)
-                               input_report_key(dev, key, !up);
+                       input_report_key(dev, key, !up);
                }
                break;
        }
- out:
-       kbd->idx4 = 0;
-       up(&kbd->sem);
+
+       input_sync(dev);
 }
 
-static void hil_kbd_process_err(struct hil_kbd *kbd)
+static void hil_dev_handle_ptr_events(struct hil_dev *ptr)
+{
+       struct input_dev *dev = ptr->dev;
+       int idx = ptr->idx4 / 4;
+       hil_packet p = ptr->data[idx - 1];
+       int i, cnt, laxis;
+       bool absdev, ax16;
+
+       if ((p & HIL_CMDCT_POL) != idx - 1) {
+               printk(KERN_WARNING PREFIX
+                       "Malformed poll packet %x (idx = %i)\n", p, idx);
+               return;
+       }
+
+       i = (p & HIL_POL_AXIS_ALT) ? 3 : 0;
+       laxis = (p & HIL_POL_NUM_AXES_MASK) + i;
+
+       ax16 = ptr->idd[1] & HIL_IDD_HEADER_16BIT; /* 8 or 16bit resolution */
+       absdev = ptr->idd[1] & HIL_IDD_HEADER_ABS;
+
+       for (cnt = 1; i < laxis; i++) {
+               unsigned int lo, hi, val;
+
+               lo = ptr->data[cnt++] & HIL_PKT_DATA_MASK;
+               hi = ax16 ? (ptr->data[cnt++] & HIL_PKT_DATA_MASK) : 0;
+
+               if (absdev) {
+                       val = lo + (hi << 8);
+#ifdef TABLET_AUTOADJUST
+                       if (val < dev->absmin[ABS_X + i])
+                               dev->absmin[ABS_X + i] = val;
+                       if (val > dev->absmax[ABS_X + i])
+                               dev->absmax[ABS_X + i] = val;
+#endif
+                       if (i%3) val = dev->absmax[ABS_X + i] - val;
+                       input_report_abs(dev, ABS_X + i, val);
+               } else {
+                       val = (int) (((int8_t)lo) | ((int8_t)hi << 8));
+                       if (i % 3)
+                               val *= -1;
+                       input_report_rel(dev, REL_X + i, val);
+               }
+       }
+
+       while (cnt < idx - 1) {
+               unsigned int btn = ptr->data[cnt++];
+               int up = btn & 1;
+
+               btn &= 0xfe;
+               if (btn == 0x8e)
+                       continue; /* TODO: proximity == touch? */
+               if (btn > 0x8c || btn < 0x80)
+                       continue;
+               btn = (btn - 0x80) >> 1;
+               btn = ptr->btnmap[btn];
+               input_report_key(dev, btn, !up);
+       }
+
+       input_sync(dev);
+}
+
+static void hil_dev_process_err(struct hil_dev *dev)
 {
        printk(KERN_WARNING PREFIX "errored HIL packet\n");
-       kbd->idx4 = 0;
-       up(&kbd->sem);
+       dev->idx4 = 0;
+       complete(&dev->cmd_done); /* just in case somebody is waiting */
 }
 
-static irqreturn_t hil_kbd_interrupt(struct serio *serio,
+static irqreturn_t hil_dev_interrupt(struct serio *serio,
                                unsigned char data, unsigned int flags)
 {
-       struct hil_kbd *kbd;
+       struct hil_dev *dev;
        hil_packet packet;
        int idx;
 
-       kbd = serio_get_drvdata(serio);
-       BUG_ON(kbd == NULL);
+       dev = serio_get_drvdata(serio);
+       BUG_ON(dev == NULL);
 
-       if (kbd->idx4 >= (HIL_KBD_MAX_LENGTH * sizeof(hil_packet))) {
-               hil_kbd_process_err(kbd);
-               return IRQ_HANDLED;
+       if (dev->idx4 >= HIL_PACKET_MAX_LENGTH * sizeof(hil_packet)) {
+               hil_dev_process_err(dev);
+               goto out;
        }
-       idx = kbd->idx4/4;
-       if (!(kbd->idx4 % 4))
-               kbd->data[idx] = 0;
-       packet = kbd->data[idx];
-       packet |= ((hil_packet)data) << ((3 - (kbd->idx4 % 4)) * 8);
-       kbd->data[idx] = packet;
+
+       idx = dev->idx4 / 4;
+       if (!(dev->idx4 % 4))
+               dev->data[idx] = 0;
+       packet = dev->data[idx];
+       packet |= ((hil_packet)data) << ((3 - (dev->idx4 % 4)) * 8);
+       dev->data[idx] = packet;
 
        /* Records of N 4-byte hil_packets must terminate with a command. */
-       if ((++(kbd->idx4)) % 4)
-               return IRQ_HANDLED;
-       if ((packet & 0xffff0000) != HIL_ERR_INT) {
-               hil_kbd_process_err(kbd);
-               return IRQ_HANDLED;
+       if ((++dev->idx4 % 4) == 0) {
+               if ((packet & 0xffff0000) != HIL_ERR_INT) {
+                       hil_dev_process_err(dev);
+               } else if (packet & HIL_PKT_CMD) {
+                       if (hil_dev_is_command_response(packet))
+                               hil_dev_handle_command_response(dev);
+                       else if (dev->is_pointer)
+                               hil_dev_handle_ptr_events(dev);
+                       else
+                               hil_dev_handle_kbd_events(dev);
+                       dev->idx4 = 0;
+               }
        }
-       if (packet & HIL_PKT_CMD)
-               hil_kbd_process_record(kbd);
+ out:
        return IRQ_HANDLED;
 }
 
-static void hil_kbd_disconnect(struct serio *serio)
+static void hil_dev_disconnect(struct serio *serio)
 {
-       struct hil_kbd *kbd;
+       struct hil_dev *dev = serio_get_drvdata(serio);
 
-       kbd = serio_get_drvdata(serio);
-       BUG_ON(kbd == NULL);
+       BUG_ON(dev == NULL);
 
        serio_close(serio);
-       input_unregister_device(kbd->dev);
-       kfree(kbd);
+       input_unregister_device(dev->dev);
+       serio_set_drvdata(serio, NULL);
+       kfree(dev);
+}
+
+static void hil_dev_keyboard_setup(struct hil_dev *kbd)
+{
+       struct input_dev *input_dev = kbd->dev;
+       uint8_t did = kbd->idd[0];
+       int i;
+
+       input_dev->evbit[0]     = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
+       input_dev->ledbit[0]    = BIT_MASK(LED_NUML) | BIT_MASK(LED_CAPSL) |
+                                 BIT_MASK(LED_SCROLLL);
+
+       for (i = 0; i < 128; i++) {
+               __set_bit(hil_kbd_set1[i], input_dev->keybit);
+               __set_bit(hil_kbd_set3[i], input_dev->keybit);
+       }
+       __clear_bit(KEY_RESERVED, input_dev->keybit);
+
+       input_dev->keycodemax   = HIL_KEYCODES_SET1_TBLSIZE;
+       input_dev->keycodesize  = sizeof(hil_kbd_set1[0]);
+       input_dev->keycode      = hil_kbd_set1;
+
+       input_dev->name = strlen(kbd->rnm) ? kbd->rnm : "HIL keyboard";
+       input_dev->phys = "hpkbd/input0";
+
+       printk(KERN_INFO PREFIX "HIL keyboard found (did = 0x%02x, lang = %s)\n",
+               did, hil_language[did & HIL_IDD_DID_TYPE_KB_LANG_MASK]);
 }
 
-static int hil_kbd_connect(struct serio *serio, struct serio_driver *drv)
+static void hil_dev_pointer_setup(struct hil_dev *ptr)
 {
-       struct hil_kbd  *kbd;
-       uint8_t         did, *idd;
-       int             i;
+       struct input_dev *input_dev = ptr->dev;
+       uint8_t did = ptr->idd[0];
+       uint8_t *idd = ptr->idd + 1;
+       unsigned int naxsets = HIL_IDD_NUM_AXSETS(*idd);
+       unsigned int i, btntype;
+       const char *txt;
+
+       ptr->naxes = HIL_IDD_NUM_AXES_PER_SET(*idd);
+
+       switch (did & HIL_IDD_DID_TYPE_MASK) {
+       case HIL_IDD_DID_TYPE_REL:
+               input_dev->evbit[0] = BIT_MASK(EV_REL);
 
-       kbd = kzalloc(sizeof(*kbd), GFP_KERNEL);
-       if (!kbd)
-               return -ENOMEM;
+               for (i = 0; i < ptr->naxes; i++)
+                       __set_bit(REL_X + i, input_dev->relbit);
 
-       kbd->dev = input_allocate_device();
-       if (!kbd->dev)
+               for (i = 3; naxsets > 1 && i < ptr->naxes + 3; i++)
+                       __set_bit(REL_X + i, input_dev->relbit);
+
+               txt = "relative";
+               break;
+
+       case HIL_IDD_DID_TYPE_ABS:
+               input_dev->evbit[0] = BIT_MASK(EV_ABS);
+
+               for (i = 0; i < ptr->naxes; i++)
+                       input_set_abs_params(input_dev, ABS_X + i,
+                                       0, HIL_IDD_AXIS_MAX(idd, i), 0, 0);
+
+               for (i = 3; naxsets > 1 && i < ptr->naxes + 3; i++)
+                       input_set_abs_params(input_dev, ABS_X + i,
+                                       0, HIL_IDD_AXIS_MAX(idd, i - 3), 0, 0);
+
+#ifdef TABLET_AUTOADJUST
+               for (i = 0; i < ABS_MAX; i++) {
+                       int diff = input_dev->absmax[ABS_X + i] / 10;
+                       input_dev->absmin[ABS_X + i] += diff;
+                       input_dev->absmax[ABS_X + i] -= diff;
+               }
+#endif
+
+               txt = "absolute";
+               break;
+
+       default:
+               BUG();
+       }
+
+       ptr->nbtn = HIL_IDD_NUM_BUTTONS(idd);
+       if (ptr->nbtn)
+               input_dev->evbit[0] |= BIT_MASK(EV_KEY);
+
+       btntype = BTN_MISC;
+       if ((did & HIL_IDD_DID_ABS_TABLET_MASK) == HIL_IDD_DID_ABS_TABLET)
+#ifdef TABLET_SIMULATES_MOUSE
+               btntype = BTN_TOUCH;
+#else
+               btntype = BTN_DIGI;
+#endif
+       if ((did & HIL_IDD_DID_ABS_TSCREEN_MASK) == HIL_IDD_DID_ABS_TSCREEN)
+               btntype = BTN_TOUCH;
+
+       if ((did & HIL_IDD_DID_REL_MOUSE_MASK) == HIL_IDD_DID_REL_MOUSE)
+               btntype = BTN_MOUSE;
+
+       for (i = 0; i < ptr->nbtn; i++) {
+               __set_bit(btntype | i, input_dev->keybit);
+               ptr->btnmap[i] = btntype | i;
+       }
+
+       if (btntype == BTN_MOUSE) {
+               /* Swap buttons 2 and 3 */
+               ptr->btnmap[1] = BTN_MIDDLE;
+               ptr->btnmap[2] = BTN_RIGHT;
+       }
+
+       input_dev->name = strlen(ptr->rnm) ? ptr->rnm : "HIL pointer device";
+
+       printk(KERN_INFO PREFIX
+               "HIL pointer device found (did: 0x%02x, axis: %s)\n",
+               did, txt);
+       printk(KERN_INFO PREFIX
+               "HIL pointer has %i buttons and %i sets of %i axes\n",
+               ptr->nbtn, naxsets, ptr->naxes);
+}
+
+static int hil_dev_connect(struct serio *serio, struct serio_driver *drv)
+{
+       struct hil_dev *dev;
+       struct input_dev *input_dev;
+       uint8_t did, *idd;
+       int error;
+
+       dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+       input_dev = input_allocate_device();
+       if (!dev || !input_dev) {
+               error = -ENOMEM;
                goto bail0;
+       }
 
-       if (serio_open(serio, drv))
-               goto bail1;
+       dev->serio = serio;
+       dev->dev = input_dev;
 
-       serio_set_drvdata(serio, kbd);
-       kbd->serio = serio;
+       error = serio_open(serio, drv);
+       if (error)
+               goto bail0;
 
-       init_MUTEX_LOCKED(&kbd->sem);
+       serio_set_drvdata(serio, dev);
 
        /* Get device info.  MLC driver supplies devid/status/etc. */
-       serio->write(serio, 0);
-       serio->write(serio, 0);
-       serio->write(serio, HIL_PKT_CMD >> 8);
-       serio->write(serio, HIL_CMD_IDD);
-       down(&kbd->sem);
-
-       serio->write(serio, 0);
-       serio->write(serio, 0);
-       serio->write(serio, HIL_PKT_CMD >> 8);
-       serio->write(serio, HIL_CMD_RSC);
-       down(&kbd->sem);
-
-       serio->write(serio, 0);
-       serio->write(serio, 0);
-       serio->write(serio, HIL_PKT_CMD >> 8);
-       serio->write(serio, HIL_CMD_RNM);
-       down(&kbd->sem);
-
-       serio->write(serio, 0);
-       serio->write(serio, 0);
-       serio->write(serio, HIL_PKT_CMD >> 8);
-       serio->write(serio, HIL_CMD_EXD);
-       down(&kbd->sem);
-
-       up(&kbd->sem);
-
-       did = kbd->idd[0];
-       idd = kbd->idd + 1;
+       init_completion(&dev->cmd_done);
+       serio_write(serio, 0);
+       serio_write(serio, 0);
+       serio_write(serio, HIL_PKT_CMD >> 8);
+       serio_write(serio, HIL_CMD_IDD);
+       error = wait_for_completion_killable(&dev->cmd_done);
+       if (error)
+               goto bail1;
+
+       init_completion(&dev->cmd_done);
+       serio_write(serio, 0);
+       serio_write(serio, 0);
+       serio_write(serio, HIL_PKT_CMD >> 8);
+       serio_write(serio, HIL_CMD_RSC);
+       error = wait_for_completion_killable(&dev->cmd_done);
+       if (error)
+               goto bail1;
+
+       init_completion(&dev->cmd_done);
+       serio_write(serio, 0);
+       serio_write(serio, 0);
+       serio_write(serio, HIL_PKT_CMD >> 8);
+       serio_write(serio, HIL_CMD_RNM);
+       error = wait_for_completion_killable(&dev->cmd_done);
+       if (error)
+               goto bail1;
+
+       init_completion(&dev->cmd_done);
+       serio_write(serio, 0);
+       serio_write(serio, 0);
+       serio_write(serio, HIL_PKT_CMD >> 8);
+       serio_write(serio, HIL_CMD_EXD);
+       error = wait_for_completion_killable(&dev->cmd_done);
+       if (error)
+               goto bail1;
+
+       did = dev->idd[0];
+       idd = dev->idd + 1;
+
        switch (did & HIL_IDD_DID_TYPE_MASK) {
        case HIL_IDD_DID_TYPE_KB_INTEGRAL:
        case HIL_IDD_DID_TYPE_KB_ITF:
        case HIL_IDD_DID_TYPE_KB_RSVD:
        case HIL_IDD_DID_TYPE_CHAR:
-               printk(KERN_INFO PREFIX "HIL keyboard found (did = 0x%02x, lang = %s)\n",
-                       did, hil_language[did & HIL_IDD_DID_TYPE_KB_LANG_MASK]);
-               break;
-       default:
-               goto bail2;
-       }
+               if (HIL_IDD_NUM_BUTTONS(idd) ||
+                   HIL_IDD_NUM_AXES_PER_SET(*idd)) {
+                       printk(KERN_INFO PREFIX
+                               "combo devices are not supported.\n");
+                       goto bail1;
+               }
 
-       if (HIL_IDD_NUM_BUTTONS(idd) || HIL_IDD_NUM_AXES_PER_SET(*idd)) {
-               printk(KERN_INFO PREFIX "keyboards only, no combo devices supported.\n");
-               goto bail2;
-       }
+               dev->is_pointer = false;
+               hil_dev_keyboard_setup(dev);
+               break;
 
-       kbd->dev->evbit[0]      = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
-       kbd->dev->ledbit[0]     = BIT_MASK(LED_NUML) | BIT_MASK(LED_CAPSL) |
-               BIT_MASK(LED_SCROLLL);
-       kbd->dev->keycodemax    = HIL_KEYCODES_SET1_TBLSIZE;
-       kbd->dev->keycodesize   = sizeof(hil_kbd_set1[0]);
-       kbd->dev->keycode       = hil_kbd_set1;
-       kbd->dev->name          = strlen(kbd->rnm) ? kbd->rnm : HIL_GENERIC_NAME;
-       kbd->dev->phys          = "hpkbd/input0";       /* XXX */
-
-       kbd->dev->id.bustype    = BUS_HIL;
-       kbd->dev->id.vendor     = PCI_VENDOR_ID_HP;
-       kbd->dev->id.product    = 0x0001; /* TODO: get from kbd->rsc */
-       kbd->dev->id.version    = 0x0100; /* TODO: get from kbd->rsc */
-       kbd->dev->dev.parent    = &serio->dev;
+       case HIL_IDD_DID_TYPE_REL:
+       case HIL_IDD_DID_TYPE_ABS:
+               dev->is_pointer = true;
+               hil_dev_pointer_setup(dev);
+               break;
 
-       for (i = 0; i < 128; i++) {
-               set_bit(hil_kbd_set1[i], kbd->dev->keybit);
-               set_bit(hil_kbd_set3[i], kbd->dev->keybit);
+       default:
+               goto bail1;
        }
-       clear_bit(0, kbd->dev->keybit);
 
-       input_register_device(kbd->dev);
-       printk(KERN_INFO "input: %s, ID: %d\n",
-               kbd->dev->name, did);
+       input_dev->id.bustype   = BUS_HIL;
+       input_dev->id.vendor    = PCI_VENDOR_ID_HP;
+       input_dev->id.product   = 0x0001; /* TODO: get from kbd->rsc */
+       input_dev->id.version   = 0x0100; /* TODO: get from kbd->rsc */
+       input_dev->dev.parent   = &serio->dev;
+
+       if (!dev->is_pointer) {
+               serio_write(serio, 0);
+               serio_write(serio, 0);
+               serio_write(serio, HIL_PKT_CMD >> 8);
+               /* Enable Keyswitch Autorepeat 1 */
+               serio_write(serio, HIL_CMD_EK1);
+               /* No need to wait for completion */
+       }
 
-       serio->write(serio, 0);
-       serio->write(serio, 0);
-       serio->write(serio, HIL_PKT_CMD >> 8);
-       serio->write(serio, HIL_CMD_EK1); /* Enable Keyswitch Autorepeat 1 */
-       down(&kbd->sem);
-       up(&kbd->sem);
+       error = input_register_device(input_dev);
+       if (error)
+               goto bail1;
 
        return 0;
- bail2:
+
+ bail1:
        serio_close(serio);
        serio_set_drvdata(serio, NULL);
- bail1:
-       input_free_device(kbd->dev);
  bail0:
-       kfree(kbd);
-       return -EIO;
+       input_free_device(input_dev);
+       kfree(dev);
+       return error;
 }
 
-static struct serio_device_id hil_kbd_ids[] = {
+static struct serio_device_id hil_dev_ids[] = {
        {
                .type = SERIO_HIL_MLC,
                .proto = SERIO_HIL,
@@ -378,26 +567,26 @@ static struct serio_device_id hil_kbd_ids[] = {
        { 0 }
 };
 
-static struct serio_driver hil_kbd_serio_drv = {
+static struct serio_driver hil_serio_drv = {
        .driver         = {
-               .name   = "hil_kbd",
+               .name   = "hil_dev",
        },
-       .description    = "HP HIL keyboard driver",
-       .id_table       = hil_kbd_ids,
-       .connect        = hil_kbd_connect,
-       .disconnect     = hil_kbd_disconnect,
-       .interrupt      = hil_kbd_interrupt
+       .description    = "HP HIL keyboard/mouse/tablet driver",
+       .id_table       = hil_dev_ids,
+       .connect        = hil_dev_connect,
+       .disconnect     = hil_dev_disconnect,
+       .interrupt      = hil_dev_interrupt
 };
 
-static int __init hil_kbd_init(void)
+static int __init hil_dev_init(void)
 {
-       return serio_register_driver(&hil_kbd_serio_drv);
+       return serio_register_driver(&hil_serio_drv);
 }
 
-static void __exit hil_kbd_exit(void)
+static void __exit hil_dev_exit(void)
 {
-       serio_unregister_driver(&hil_kbd_serio_drv);
+       serio_unregister_driver(&hil_serio_drv);
 }
 
-module_init(hil_kbd_init);
-module_exit(hil_kbd_exit);
+module_init(hil_dev_init);
+module_exit(hil_dev_exit);
index 4730ef35c732dbc1210fb2a5b0adc3e4551b6caf..f9847e0fb5539011be9eb92590887d00a29ab73e 100644 (file)
@@ -525,12 +525,12 @@ lkkbd_event (struct input_dev *dev, unsigned int type, unsigned int code,
                        CHECK_LED (lk, leds_on, leds_off, LED_SCROLLL, LK_LED_SCROLLLOCK);
                        CHECK_LED (lk, leds_on, leds_off, LED_SLEEP, LK_LED_WAIT);
                        if (leds_on != 0) {
-                               lk->serio->write (lk->serio, LK_CMD_LED_ON);
-                               lk->serio->write (lk->serio, leds_on);
+                               serio_write (lk->serio, LK_CMD_LED_ON);
+                               serio_write (lk->serio, leds_on);
                        }
                        if (leds_off != 0) {
-                               lk->serio->write (lk->serio, LK_CMD_LED_OFF);
-                               lk->serio->write (lk->serio, leds_off);
+                               serio_write (lk->serio, LK_CMD_LED_OFF);
+                               serio_write (lk->serio, leds_off);
                        }
                        return 0;
 
@@ -539,20 +539,20 @@ lkkbd_event (struct input_dev *dev, unsigned int type, unsigned int code,
                                case SND_CLICK:
                                        if (value == 0) {
                                                DBG ("%s: Deactivating key clicks\n", __func__);
-                                               lk->serio->write (lk->serio, LK_CMD_DISABLE_KEYCLICK);
-                                               lk->serio->write (lk->serio, LK_CMD_DISABLE_CTRCLICK);
+                                               serio_write (lk->serio, LK_CMD_DISABLE_KEYCLICK);
+                                               serio_write (lk->serio, LK_CMD_DISABLE_CTRCLICK);
                                        } else {
                                                DBG ("%s: Activating key clicks\n", __func__);
-                                               lk->serio->write (lk->serio, LK_CMD_ENABLE_KEYCLICK);
-                                               lk->serio->write (lk->serio, volume_to_hw (lk->keyclick_volume));
-                                               lk->serio->write (lk->serio, LK_CMD_ENABLE_CTRCLICK);
-                                               lk->serio->write (lk->serio, volume_to_hw (lk->ctrlclick_volume));
+                                               serio_write (lk->serio, LK_CMD_ENABLE_KEYCLICK);
+                                               serio_write (lk->serio, volume_to_hw (lk->keyclick_volume));
+                                               serio_write (lk->serio, LK_CMD_ENABLE_CTRCLICK);
+                                               serio_write (lk->serio, volume_to_hw (lk->ctrlclick_volume));
                                        }
                                        return 0;
 
                                case SND_BELL:
                                        if (value != 0)
-                                               lk->serio->write (lk->serio, LK_CMD_SOUND_BELL);
+                                               serio_write (lk->serio, LK_CMD_SOUND_BELL);
 
                                        return 0;
                        }
@@ -579,10 +579,10 @@ lkkbd_reinit (struct work_struct *work)
        unsigned char leds_off = 0;
 
        /* Ask for ID */
-       lk->serio->write (lk->serio, LK_CMD_REQUEST_ID);
+       serio_write (lk->serio, LK_CMD_REQUEST_ID);
 
        /* Reset parameters */
-       lk->serio->write (lk->serio, LK_CMD_SET_DEFAULTS);
+       serio_write (lk->serio, LK_CMD_SET_DEFAULTS);
 
        /* Set LEDs */
        CHECK_LED (lk, leds_on, leds_off, LED_CAPSL, LK_LED_SHIFTLOCK);
@@ -590,12 +590,12 @@ lkkbd_reinit (struct work_struct *work)
        CHECK_LED (lk, leds_on, leds_off, LED_SCROLLL, LK_LED_SCROLLLOCK);
        CHECK_LED (lk, leds_on, leds_off, LED_SLEEP, LK_LED_WAIT);
        if (leds_on != 0) {
-               lk->serio->write (lk->serio, LK_CMD_LED_ON);
-               lk->serio->write (lk->serio, leds_on);
+               serio_write (lk->serio, LK_CMD_LED_ON);
+               serio_write (lk->serio, leds_on);
        }
        if (leds_off != 0) {
-               lk->serio->write (lk->serio, LK_CMD_LED_OFF);
-               lk->serio->write (lk->serio, leds_off);
+               serio_write (lk->serio, LK_CMD_LED_OFF);
+               serio_write (lk->serio, leds_off);
        }
 
        /*
@@ -603,31 +603,31 @@ lkkbd_reinit (struct work_struct *work)
         * only work with a LK401 keyboard and grants access to
         * LAlt, RAlt, RCompose and RShift.
         */
-       lk->serio->write (lk->serio, LK_CMD_ENABLE_LK401);
+       serio_write (lk->serio, LK_CMD_ENABLE_LK401);
 
        /* Set all keys to UPDOWN mode */
        for (division = 1; division <= 14; division++)
-               lk->serio->write (lk->serio, LK_CMD_SET_MODE (LK_MODE_UPDOWN,
+               serio_write (lk->serio, LK_CMD_SET_MODE (LK_MODE_UPDOWN,
                                        division));
 
        /* Enable bell and set volume */
-       lk->serio->write (lk->serio, LK_CMD_ENABLE_BELL);
-       lk->serio->write (lk->serio, volume_to_hw (lk->bell_volume));
+       serio_write (lk->serio, LK_CMD_ENABLE_BELL);
+       serio_write (lk->serio, volume_to_hw (lk->bell_volume));
 
        /* Enable/disable keyclick (and possibly set volume) */
        if (test_bit (SND_CLICK, lk->dev->snd)) {
-               lk->serio->write (lk->serio, LK_CMD_ENABLE_KEYCLICK);
-               lk->serio->write (lk->serio, volume_to_hw (lk->keyclick_volume));
-               lk->serio->write (lk->serio, LK_CMD_ENABLE_CTRCLICK);
-               lk->serio->write (lk->serio, volume_to_hw (lk->ctrlclick_volume));
+               serio_write (lk->serio, LK_CMD_ENABLE_KEYCLICK);
+               serio_write (lk->serio, volume_to_hw (lk->keyclick_volume));
+               serio_write (lk->serio, LK_CMD_ENABLE_CTRCLICK);
+               serio_write (lk->serio, volume_to_hw (lk->ctrlclick_volume));
        } else {
-               lk->serio->write (lk->serio, LK_CMD_DISABLE_KEYCLICK);
-               lk->serio->write (lk->serio, LK_CMD_DISABLE_CTRCLICK);
+               serio_write (lk->serio, LK_CMD_DISABLE_KEYCLICK);
+               serio_write (lk->serio, LK_CMD_DISABLE_CTRCLICK);
        }
 
        /* Sound the bell if needed */
        if (test_bit (SND_BELL, lk->dev->snd))
-               lk->serio->write (lk->serio, LK_CMD_SOUND_BELL);
+               serio_write (lk->serio, LK_CMD_SOUND_BELL);
 }
 
 /*
@@ -684,8 +684,10 @@ lkkbd_connect (struct serio *serio, struct serio_driver *drv)
        input_dev->keycode = lk->keycode;
        input_dev->keycodesize = sizeof (lk_keycode_t);
        input_dev->keycodemax = LK_NUM_KEYCODES;
+
        for (i = 0; i < LK_NUM_KEYCODES; i++)
-               set_bit (lk->keycode[i], input_dev->keybit);
+               __set_bit (lk->keycode[i], input_dev->keybit);
+       __clear_bit(KEY_RESERVED, input_dev->keybit);
 
        serio_set_drvdata (serio, lk);
 
@@ -697,7 +699,7 @@ lkkbd_connect (struct serio *serio, struct serio_driver *drv)
        if (err)
                goto fail3;
 
-       lk->serio->write (lk->serio, LK_CMD_POWERCYCLE_RESET);
+       serio_write (lk->serio, LK_CMD_POWERCYCLE_RESET);
 
        return 0;
 
index 541b981ff0752d2a3bfeb991ad1bf866d236aa61..91cfe51702657573fb1519bc59d5f0e42c476ddc 100644 (file)
@@ -319,7 +319,6 @@ static int __devinit matrix_keypad_probe(struct platform_device *pdev)
        struct input_dev *input_dev;
        unsigned short *keycodes;
        unsigned int row_shift;
-       int i;
        int err;
 
        pdata = pdev->dev.platform_data;
@@ -363,18 +362,10 @@ static int __devinit matrix_keypad_probe(struct platform_device *pdev)
 
        input_dev->keycode      = keycodes;
        input_dev->keycodesize  = sizeof(*keycodes);
-       input_dev->keycodemax   = pdata->num_row_gpios << keypad->row_shift;
-
-       for (i = 0; i < keymap_data->keymap_size; i++) {
-               unsigned int key = keymap_data->keymap[i];
-               unsigned int row = KEY_ROW(key);
-               unsigned int col = KEY_COL(key);
-               unsigned short code = KEY_VAL(key);
+       input_dev->keycodemax   = pdata->num_row_gpios << row_shift;
 
-               keycodes[MATRIX_SCAN_CODE(row, col, row_shift)] = code;
-               __set_bit(code, input_dev->keybit);
-       }
-       __clear_bit(KEY_RESERVED, input_dev->keybit);
+       matrix_keypad_build_keymap(keymap_data, row_shift,
+                                  input_dev->keycode, input_dev->keybit);
 
        input_set_capability(input_dev, EV_MSC, MSC_SCAN);
        input_set_drvdata(input_dev, keypad);
index 0d2fc64a5e1cead895be0a0c22cd96a500faf1c0..76f9668221a423926e7e19dfb5a0a6e823b487d2 100644 (file)
 #include <linux/platform_device.h>
 #include <linux/clk.h>
 #include <linux/err.h>
+#include <linux/input/matrix_keypad.h>
 
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 
 #include <mach/hardware.h>
 #include <mach/pxa27x_keypad.h>
-
 /*
  * Keypad Controller registers
  */
@@ -95,7 +95,8 @@
 #define keypad_readl(off)      __raw_readl(keypad->mmio_base + (off))
 #define keypad_writel(off, v)  __raw_writel((v), keypad->mmio_base + (off))
 
-#define MAX_MATRIX_KEY_NUM     (8 * 8)
+#define MAX_MATRIX_KEY_NUM     (MAX_MATRIX_KEY_ROWS * MAX_MATRIX_KEY_COLS)
+#define MAX_KEYPAD_KEYS                (MAX_MATRIX_KEY_NUM + MAX_DIRECT_KEY_NUM)
 
 struct pxa27x_keypad {
        struct pxa27x_keypad_platform_data *pdata;
@@ -106,73 +107,82 @@ struct pxa27x_keypad {
 
        int irq;
 
-       /* matrix key code map */
-       unsigned int matrix_keycodes[MAX_MATRIX_KEY_NUM];
+       unsigned short keycodes[MAX_KEYPAD_KEYS];
+       int rotary_rel_code[2];
 
        /* state row bits of each column scan */
        uint32_t matrix_key_state[MAX_MATRIX_KEY_COLS];
        uint32_t direct_key_state;
 
        unsigned int direct_key_mask;
-
-       int rotary_rel_code[2];
-       int rotary_up_key[2];
-       int rotary_down_key[2];
 };
 
 static void pxa27x_keypad_build_keycode(struct pxa27x_keypad *keypad)
 {
        struct pxa27x_keypad_platform_data *pdata = keypad->pdata;
        struct input_dev *input_dev = keypad->input_dev;
-       unsigned int *key;
+       unsigned short keycode;
        int i;
 
-       key = &pdata->matrix_key_map[0];
-       for (i = 0; i < pdata->matrix_key_map_size; i++, key++) {
-               int row = ((*key) >> 28) & 0xf;
-               int col = ((*key) >> 24) & 0xf;
-               int code = (*key) & 0xffffff;
+       for (i = 0; i < pdata->matrix_key_map_size; i++) {
+               unsigned int key = pdata->matrix_key_map[i];
+               unsigned int row = KEY_ROW(key);
+               unsigned int col = KEY_COL(key);
+               unsigned int scancode = MATRIX_SCAN_CODE(row, col,
+                                                        MATRIX_ROW_SHIFT);
 
-               keypad->matrix_keycodes[(row << 3) + col] = code;
-               set_bit(code, input_dev->keybit);
+               keycode = KEY_VAL(key);
+               keypad->keycodes[scancode] = keycode;
+               __set_bit(keycode, input_dev->keybit);
        }
 
-       for (i = 0; i < pdata->direct_key_num; i++)
-               set_bit(pdata->direct_key_map[i], input_dev->keybit);
-
-       keypad->rotary_up_key[0] = pdata->rotary0_up_key;
-       keypad->rotary_up_key[1] = pdata->rotary1_up_key;
-       keypad->rotary_down_key[0] = pdata->rotary0_down_key;
-       keypad->rotary_down_key[1] = pdata->rotary1_down_key;
-       keypad->rotary_rel_code[0] = pdata->rotary0_rel_code;
-       keypad->rotary_rel_code[1] = pdata->rotary1_rel_code;
+       for (i = 0; i < pdata->direct_key_num; i++) {
+               keycode = pdata->direct_key_map[i];
+               keypad->keycodes[MAX_MATRIX_KEY_NUM + i] = keycode;
+               __set_bit(keycode, input_dev->keybit);
+       }
 
        if (pdata->enable_rotary0) {
                if (pdata->rotary0_up_key && pdata->rotary0_down_key) {
-                       set_bit(pdata->rotary0_up_key, input_dev->keybit);
-                       set_bit(pdata->rotary0_down_key, input_dev->keybit);
-               } else
-                       set_bit(pdata->rotary0_rel_code, input_dev->relbit);
+                       keycode = pdata->rotary0_up_key;
+                       keypad->keycodes[MAX_MATRIX_KEY_NUM + 0] = keycode;
+                       __set_bit(keycode, input_dev->keybit);
+
+                       keycode = pdata->rotary0_down_key;
+                       keypad->keycodes[MAX_MATRIX_KEY_NUM + 1] = keycode;
+                       __set_bit(keycode, input_dev->keybit);
+
+                       keypad->rotary_rel_code[0] = -1;
+               } else {
+                       keypad->rotary_rel_code[0] = pdata->rotary0_rel_code;
+                       __set_bit(pdata->rotary0_rel_code, input_dev->relbit);
+               }
        }
 
        if (pdata->enable_rotary1) {
                if (pdata->rotary1_up_key && pdata->rotary1_down_key) {
-                       set_bit(pdata->rotary1_up_key, input_dev->keybit);
-                       set_bit(pdata->rotary1_down_key, input_dev->keybit);
-               } else
-                       set_bit(pdata->rotary1_rel_code, input_dev->relbit);
+                       keycode = pdata->rotary1_up_key;
+                       keypad->keycodes[MAX_MATRIX_KEY_NUM + 2] = keycode;
+                       __set_bit(keycode, input_dev->keybit);
+
+                       keycode = pdata->rotary1_down_key;
+                       keypad->keycodes[MAX_MATRIX_KEY_NUM + 3] = keycode;
+                       __set_bit(keycode, input_dev->keybit);
+
+                       keypad->rotary_rel_code[1] = -1;
+               } else {
+                       keypad->rotary_rel_code[1] = pdata->rotary1_rel_code;
+                       __set_bit(pdata->rotary1_rel_code, input_dev->relbit);
+               }
        }
-}
 
-static inline unsigned int lookup_matrix_keycode(
-               struct pxa27x_keypad *keypad, int row, int col)
-{
-       return keypad->matrix_keycodes[(row << 3) + col];
+       __clear_bit(KEY_RESERVED, input_dev->keybit);
 }
 
 static void pxa27x_keypad_scan_matrix(struct pxa27x_keypad *keypad)
 {
        struct pxa27x_keypad_platform_data *pdata = keypad->pdata;
+       struct input_dev *input_dev = keypad->input_dev;
        int row, col, num_keys_pressed = 0;
        uint32_t new_state[MAX_MATRIX_KEY_COLS];
        uint32_t kpas = keypad_readl(KPAS);
@@ -215,6 +225,7 @@ static void pxa27x_keypad_scan_matrix(struct pxa27x_keypad *keypad)
 scan:
        for (col = 0; col < pdata->matrix_key_cols; col++) {
                uint32_t bits_changed;
+               int code;
 
                bits_changed = keypad->matrix_key_state[col] ^ new_state[col];
                if (bits_changed == 0)
@@ -224,12 +235,13 @@ scan:
                        if ((bits_changed & (1 << row)) == 0)
                                continue;
 
-                       input_report_key(keypad->input_dev,
-                               lookup_matrix_keycode(keypad, row, col),
-                               new_state[col] & (1 << row));
+                       code = MATRIX_SCAN_CODE(row, col, MATRIX_ROW_SHIFT);
+                       input_event(input_dev, EV_MSC, MSC_SCAN, code);
+                       input_report_key(input_dev, keypad->keycodes[code],
+                                        new_state[col] & (1 << row));
                }
        }
-       input_sync(keypad->input_dev);
+       input_sync(input_dev);
        memcpy(keypad->matrix_key_state, new_state, sizeof(new_state));
 }
 
@@ -252,13 +264,15 @@ static void report_rotary_event(struct pxa27x_keypad *keypad, int r, int delta)
        if (delta == 0)
                return;
 
-       if (keypad->rotary_up_key[r] && keypad->rotary_down_key[r]) {
-               int keycode = (delta > 0) ? keypad->rotary_up_key[r] :
-                                           keypad->rotary_down_key[r];
+       if (keypad->rotary_rel_code[r] == -1) {
+               int code = MAX_MATRIX_KEY_NUM + 2 * r + (delta > 0 ? 0 : 1);
+               unsigned char keycode = keypad->keycodes[code];
 
                /* simulate a press-n-release */
+               input_event(dev, EV_MSC, MSC_SCAN, code);
                input_report_key(dev, keycode, 1);
                input_sync(dev);
+               input_event(dev, EV_MSC, MSC_SCAN, code);
                input_report_key(dev, keycode, 0);
                input_sync(dev);
        } else {
@@ -286,6 +300,7 @@ static void pxa27x_keypad_scan_rotary(struct pxa27x_keypad *keypad)
 static void pxa27x_keypad_scan_direct(struct pxa27x_keypad *keypad)
 {
        struct pxa27x_keypad_platform_data *pdata = keypad->pdata;
+       struct input_dev *input_dev = keypad->input_dev;
        unsigned int new_state;
        uint32_t kpdk, bits_changed;
        int i;
@@ -295,9 +310,6 @@ static void pxa27x_keypad_scan_direct(struct pxa27x_keypad *keypad)
        if (pdata->enable_rotary0 || pdata->enable_rotary1)
                pxa27x_keypad_scan_rotary(keypad);
 
-       if (pdata->direct_key_map == NULL)
-               return;
-
        new_state = KPDK_DK(kpdk) & keypad->direct_key_mask;
        bits_changed = keypad->direct_key_state ^ new_state;
 
@@ -305,12 +317,15 @@ static void pxa27x_keypad_scan_direct(struct pxa27x_keypad *keypad)
                return;
 
        for (i = 0; i < pdata->direct_key_num; i++) {
-               if (bits_changed & (1 << i))
-                       input_report_key(keypad->input_dev,
-                                       pdata->direct_key_map[i],
-                                       (new_state & (1 << i)));
+               if (bits_changed & (1 << i)) {
+                       int code = MAX_MATRIX_KEY_NUM + i;
+
+                       input_event(input_dev, EV_MSC, MSC_SCAN, code);
+                       input_report_key(input_dev, keypad->keycodes[code],
+                                        new_state & (1 << i));
+               }
        }
-       input_sync(keypad->input_dev);
+       input_sync(input_dev);
        keypad->direct_key_state = new_state;
 }
 
@@ -388,8 +403,9 @@ static void pxa27x_keypad_close(struct input_dev *dev)
 }
 
 #ifdef CONFIG_PM
-static int pxa27x_keypad_suspend(struct platform_device *pdev, pm_message_t state)
+static int pxa27x_keypad_suspend(struct device *dev)
 {
+       struct platform_device *pdev = to_platform_device(dev);
        struct pxa27x_keypad *keypad = platform_get_drvdata(pdev);
 
        clk_disable(keypad->clk);
@@ -400,8 +416,9 @@ static int pxa27x_keypad_suspend(struct platform_device *pdev, pm_message_t stat
        return 0;
 }
 
-static int pxa27x_keypad_resume(struct platform_device *pdev)
+static int pxa27x_keypad_resume(struct device *dev)
 {
+       struct platform_device *pdev = to_platform_device(dev);
        struct pxa27x_keypad *keypad = platform_get_drvdata(pdev);
        struct input_dev *input_dev = keypad->input_dev;
 
@@ -420,55 +437,58 @@ static int pxa27x_keypad_resume(struct platform_device *pdev)
 
        return 0;
 }
-#else
-#define pxa27x_keypad_suspend  NULL
-#define pxa27x_keypad_resume   NULL
-#endif
 
-#define res_size(res)  ((res)->end - (res)->start + 1)
+static const struct dev_pm_ops pxa27x_keypad_pm_ops = {
+       .suspend        = pxa27x_keypad_suspend,
+       .resume         = pxa27x_keypad_resume,
+};
+#endif
 
 static int __devinit pxa27x_keypad_probe(struct platform_device *pdev)
 {
+       struct pxa27x_keypad_platform_data *pdata = pdev->dev.platform_data;
        struct pxa27x_keypad *keypad;
        struct input_dev *input_dev;
        struct resource *res;
        int irq, error;
 
-       keypad = kzalloc(sizeof(struct pxa27x_keypad), GFP_KERNEL);
-       if (keypad == NULL) {
-               dev_err(&pdev->dev, "failed to allocate driver data\n");
-               return -ENOMEM;
-       }
-
-       keypad->pdata = pdev->dev.platform_data;
-       if (keypad->pdata == NULL) {
+       if (pdata == NULL) {
                dev_err(&pdev->dev, "no platform data defined\n");
-               error = -EINVAL;
-               goto failed_free;
+               return -EINVAL;
        }
 
        irq = platform_get_irq(pdev, 0);
        if (irq < 0) {
                dev_err(&pdev->dev, "failed to get keypad irq\n");
-               error = -ENXIO;
-               goto failed_free;
+               return -ENXIO;
        }
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (res == NULL) {
                dev_err(&pdev->dev, "failed to get I/O memory\n");
-               error = -ENXIO;
+               return -ENXIO;
+       }
+
+       keypad = kzalloc(sizeof(struct pxa27x_keypad), GFP_KERNEL);
+       input_dev = input_allocate_device();
+       if (!keypad || !input_dev) {
+               dev_err(&pdev->dev, "failed to allocate memory\n");
+               error = -ENOMEM;
                goto failed_free;
        }
 
-       res = request_mem_region(res->start, res_size(res), pdev->name);
+       keypad->pdata = pdata;
+       keypad->input_dev = input_dev;
+       keypad->irq = irq;
+
+       res = request_mem_region(res->start, resource_size(res), pdev->name);
        if (res == NULL) {
                dev_err(&pdev->dev, "failed to request I/O memory\n");
                error = -EBUSY;
                goto failed_free;
        }
 
-       keypad->mmio_base = ioremap(res->start, res_size(res));
+       keypad->mmio_base = ioremap(res->start, resource_size(res));
        if (keypad->mmio_base == NULL) {
                dev_err(&pdev->dev, "failed to remap I/O memory\n");
                error = -ENXIO;
@@ -482,43 +502,35 @@ static int __devinit pxa27x_keypad_probe(struct platform_device *pdev)
                goto failed_free_io;
        }
 
-       /* Create and register the input driver. */
-       input_dev = input_allocate_device();
-       if (!input_dev) {
-               dev_err(&pdev->dev, "failed to allocate input device\n");
-               error = -ENOMEM;
-               goto failed_put_clk;
-       }
-
        input_dev->name = pdev->name;
        input_dev->id.bustype = BUS_HOST;
        input_dev->open = pxa27x_keypad_open;
        input_dev->close = pxa27x_keypad_close;
        input_dev->dev.parent = &pdev->dev;
 
-       keypad->input_dev = input_dev;
+       input_dev->keycode = keypad->keycodes;
+       input_dev->keycodesize = sizeof(keypad->keycodes[0]);
+       input_dev->keycodemax = ARRAY_SIZE(keypad->keycodes);
+
        input_set_drvdata(input_dev, keypad);
 
        input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
-       if ((keypad->pdata->enable_rotary0 &&
-                       keypad->pdata->rotary0_rel_code) ||
-           (keypad->pdata->enable_rotary1 &&
-                       keypad->pdata->rotary1_rel_code)) {
-               input_dev->evbit[0] |= BIT_MASK(EV_REL);
-       }
+       input_set_capability(input_dev, EV_MSC, MSC_SCAN);
 
        pxa27x_keypad_build_keycode(keypad);
-       platform_set_drvdata(pdev, keypad);
+
+       if ((pdata->enable_rotary0 && keypad->rotary_rel_code[0] != -1) ||
+           (pdata->enable_rotary1 && keypad->rotary_rel_code[1] != -1)) {
+               input_dev->evbit[0] |= BIT_MASK(EV_REL);
+       }
 
        error = request_irq(irq, pxa27x_keypad_irq_handler, IRQF_DISABLED,
                            pdev->name, keypad);
        if (error) {
                dev_err(&pdev->dev, "failed to request IRQ\n");
-               goto failed_free_dev;
+               goto failed_put_clk;
        }
 
-       keypad->irq = irq;
-
        /* Register the input device */
        error = input_register_device(input_dev);
        if (error) {
@@ -526,22 +538,21 @@ static int __devinit pxa27x_keypad_probe(struct platform_device *pdev)
                goto failed_free_irq;
        }
 
+       platform_set_drvdata(pdev, keypad);
        device_init_wakeup(&pdev->dev, 1);
 
        return 0;
 
 failed_free_irq:
        free_irq(irq, pdev);
-       platform_set_drvdata(pdev, NULL);
-failed_free_dev:
-       input_free_device(input_dev);
 failed_put_clk:
        clk_put(keypad->clk);
 failed_free_io:
        iounmap(keypad->mmio_base);
 failed_free_mem:
-       release_mem_region(res->start, res_size(res));
+       release_mem_region(res->start, resource_size(res));
 failed_free:
+       input_free_device(input_dev);
        kfree(keypad);
        return error;
 }
@@ -552,8 +563,6 @@ static int __devexit pxa27x_keypad_remove(struct platform_device *pdev)
        struct resource *res;
 
        free_irq(keypad->irq, pdev);
-
-       clk_disable(keypad->clk);
        clk_put(keypad->clk);
 
        input_unregister_device(keypad->input_dev);
@@ -562,10 +571,11 @@ static int __devexit pxa27x_keypad_remove(struct platform_device *pdev)
        iounmap(keypad->mmio_base);
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       release_mem_region(res->start, res_size(res));
+       release_mem_region(res->start, resource_size(res));
 
        platform_set_drvdata(pdev, NULL);
        kfree(keypad);
+
        return 0;
 }
 
@@ -575,11 +585,12 @@ MODULE_ALIAS("platform:pxa27x-keypad");
 static struct platform_driver pxa27x_keypad_driver = {
        .probe          = pxa27x_keypad_probe,
        .remove         = __devexit_p(pxa27x_keypad_remove),
-       .suspend        = pxa27x_keypad_suspend,
-       .resume         = pxa27x_keypad_resume,
        .driver         = {
                .name   = "pxa27x-keypad",
                .owner  = THIS_MODULE,
+#ifdef CONFIG_PM
+               .pm     = &pxa27x_keypad_pm_ops,
+#endif
        },
 };
 
index cea70e6a1031a12d91346756b7fec83faab1324f..0714bf2c28fcb513a22c8c17a288e4b8b7a85735 100644 (file)
@@ -128,7 +128,7 @@ static int __devinit sh_keysc_probe(struct platform_device *pdev)
        struct resource *res;
        struct input_dev *input;
        char clk_name[8];
-       int i, k;
+       int i;
        int irq, error;
 
        if (!pdev->dev.platform_data) {
@@ -195,17 +195,19 @@ static int __devinit sh_keysc_probe(struct platform_device *pdev)
        input->id.product = 0x0001;
        input->id.version = 0x0100;
 
+       input->keycode = pdata->keycodes;
+       input->keycodesize = sizeof(pdata->keycodes[0]);
+       input->keycodemax = ARRAY_SIZE(pdata->keycodes);
+
        error = request_irq(irq, sh_keysc_isr, 0, pdev->name, pdev);
        if (error) {
                dev_err(&pdev->dev, "failed to request IRQ\n");
                goto err4;
        }
 
-       for (i = 0; i < SH_KEYSC_MAXKEYS; i++) {
-               k = pdata->keycodes[i];
-               if (k)
-                       input_set_capability(input, EV_KEY, k);
-       }
+       for (i = 0; i < SH_KEYSC_MAXKEYS; i++)
+               __set_bit(pdata->keycodes[i], input->keybit);
+       __clear_bit(KEY_RESERVED, input->keybit);
 
        error = input_register_device(input);
        if (error) {
@@ -221,7 +223,9 @@ static int __devinit sh_keysc_probe(struct platform_device *pdev)
        iowrite16(KYCR2_IRQ_LEVEL, priv->iomem_base + KYCR2_OFFS);
 
        device_init_wakeup(&pdev->dev, 1);
+
        return 0;
+
  err5:
        free_irq(irq, pdev);
  err4:
@@ -252,6 +256,7 @@ static int __devexit sh_keysc_remove(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, NULL);
        kfree(priv);
+
        return 0;
 }
 
@@ -267,11 +272,12 @@ static int sh_keysc_suspend(struct device *dev)
        if (device_may_wakeup(dev)) {
                value |= 0x80;
                enable_irq_wake(irq);
-       }
-       else
+       } else {
                value &= ~0x80;
+       }
 
        iowrite16(value, priv->iomem_base + KYCR1_OFFS);
+
        return 0;
 }
 
index 9fce6d1e29b20bbc2e03f6e3e1a3d39f93c61b9d..472b56639cdb2d1b08ab1a4ae078fd5c5016fc9f 100644 (file)
@@ -73,7 +73,7 @@ static unsigned char sunkbd_keycode[128] = {
  */
 
 struct sunkbd {
-       unsigned char keycode[128];
+       unsigned char keycode[ARRAY_SIZE(sunkbd_keycode)];
        struct input_dev *dev;
        struct serio *serio;
        struct work_struct tq;
@@ -81,7 +81,7 @@ struct sunkbd {
        char name[64];
        char phys[32];
        char type;
-       unsigned char enabled;
+       bool enabled;
        volatile s8 reset;
        volatile s8 layout;
 };
@@ -94,10 +94,14 @@ struct sunkbd {
 static irqreturn_t sunkbd_interrupt(struct serio *serio,
                unsigned char data, unsigned int flags)
 {
-       struct sunkbdsunkbd = serio_get_drvdata(serio);
+       struct sunkbd *sunkbd = serio_get_drvdata(serio);
 
-       if (sunkbd->reset <= -1) {              /* If cp[i] is 0xff, sunkbd->reset will stay -1. */
-               sunkbd->reset = data;           /* The keyboard sends 0xff 0xff 0xID on powerup */
+       if (sunkbd->reset <= -1) {
+               /*
+                * If cp[i] is 0xff, sunkbd->reset will stay -1.
+                * The keyboard sends 0xff 0xff 0xID on powerup.
+                */
+               sunkbd->reset = data;
                wake_up_interruptible(&sunkbd->wait);
                goto out;
        }
@@ -110,29 +114,33 @@ static irqreturn_t sunkbd_interrupt(struct serio *serio,
 
        switch (data) {
 
-               case SUNKBD_RET_RESET:
-                       schedule_work(&sunkbd->tq);
-                       sunkbd->reset = -1;
-                       break;
+       case SUNKBD_RET_RESET:
+               schedule_work(&sunkbd->tq);
+               sunkbd->reset = -1;
+               break;
 
-               case SUNKBD_RET_LAYOUT:
-                       sunkbd->layout = -1;
-                       break;
+       case SUNKBD_RET_LAYOUT:
+               sunkbd->layout = -1;
+               break;
+
+       case SUNKBD_RET_ALLUP: /* All keys released */
+               break;
 
-               case SUNKBD_RET_ALLUP: /* All keys released */
+       default:
+               if (!sunkbd->enabled)
                        break;
 
-               default:
-                       if (!sunkbd->enabled)
-                               break;
-
-                       if (sunkbd->keycode[data & SUNKBD_KEY]) {
-                                input_report_key(sunkbd->dev, sunkbd->keycode[data & SUNKBD_KEY], !(data & SUNKBD_RELEASE));
-                               input_sync(sunkbd->dev);
-                        } else {
-                                printk(KERN_WARNING "sunkbd.c: Unknown key (scancode %#x) %s.\n",
-                                        data & SUNKBD_KEY, data & SUNKBD_RELEASE ? "released" : "pressed");
-                        }
+               if (sunkbd->keycode[data & SUNKBD_KEY]) {
+                       input_report_key(sunkbd->dev,
+                                        sunkbd->keycode[data & SUNKBD_KEY],
+                                        !(data & SUNKBD_RELEASE));
+                       input_sync(sunkbd->dev);
+               } else {
+                       printk(KERN_WARNING
+                               "sunkbd.c: Unknown key (scancode %#x) %s.\n",
+                               data & SUNKBD_KEY,
+                               data & SUNKBD_RELEASE ? "released" : "pressed");
+               }
        }
 out:
        return IRQ_HANDLED;
@@ -142,34 +150,37 @@ out:
  * sunkbd_event() handles events from the input module.
  */
 
-static int sunkbd_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
+static int sunkbd_event(struct input_dev *dev,
+                       unsigned int type, unsigned int code, int value)
 {
        struct sunkbd *sunkbd = input_get_drvdata(dev);
 
        switch (type) {
 
-               case EV_LED:
+       case EV_LED:
 
-                       sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_SETLED);
-                       sunkbd->serio->write(sunkbd->serio,
-                               (!!test_bit(LED_CAPSL, dev->led) << 3) | (!!test_bit(LED_SCROLLL, dev->led) << 2) |
-                               (!!test_bit(LED_COMPOSE, dev->led) << 1) | !!test_bit(LED_NUML, dev->led));
-                       return 0;
+               serio_write(sunkbd->serio, SUNKBD_CMD_SETLED);
+               serio_write(sunkbd->serio,
+                       (!!test_bit(LED_CAPSL,   dev->led) << 3) |
+                       (!!test_bit(LED_SCROLLL, dev->led) << 2) |
+                       (!!test_bit(LED_COMPOSE, dev->led) << 1) |
+                        !!test_bit(LED_NUML,    dev->led));
+               return 0;
 
-               case EV_SND:
+       case EV_SND:
 
-                       switch (code) {
+               switch (code) {
 
-                               case SND_CLICK:
-                                       sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_NOCLICK - value);
-                                       return 0;
+               case SND_CLICK:
+                       serio_write(sunkbd->serio, SUNKBD_CMD_NOCLICK - value);
+                       return 0;
 
-                               case SND_BELL:
-                                       sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_BELLOFF - value);
-                                       return 0;
-                       }
+               case SND_BELL:
+                       serio_write(sunkbd->serio, SUNKBD_CMD_BELLOFF - value);
+                       return 0;
+               }
 
-                       break;
+               break;
        }
 
        return -1;
@@ -183,7 +194,7 @@ static int sunkbd_event(struct input_dev *dev, unsigned int type, unsigned int c
 static int sunkbd_initialize(struct sunkbd *sunkbd)
 {
        sunkbd->reset = -2;
-       sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_RESET);
+       serio_write(sunkbd->serio, SUNKBD_CMD_RESET);
        wait_event_interruptible_timeout(sunkbd->wait, sunkbd->reset >= 0, HZ);
        if (sunkbd->reset < 0)
                return -1;
@@ -192,10 +203,13 @@ static int sunkbd_initialize(struct sunkbd *sunkbd)
 
        if (sunkbd->type == 4) {        /* Type 4 keyboard */
                sunkbd->layout = -2;
-               sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_LAYOUT);
-               wait_event_interruptible_timeout(sunkbd->wait, sunkbd->layout >= 0, HZ/4);
-               if (sunkbd->layout < 0) return -1;
-               if (sunkbd->layout & SUNKBD_LAYOUT_5_MASK) sunkbd->type = 5;
+               serio_write(sunkbd->serio, SUNKBD_CMD_LAYOUT);
+               wait_event_interruptible_timeout(sunkbd->wait,
+                                                sunkbd->layout >= 0, HZ / 4);
+               if (sunkbd->layout < 0)
+                       return -1;
+               if (sunkbd->layout & SUNKBD_LAYOUT_5_MASK)
+                       sunkbd->type = 5;
        }
 
        return 0;
@@ -212,15 +226,19 @@ static void sunkbd_reinit(struct work_struct *work)
 
        wait_event_interruptible_timeout(sunkbd->wait, sunkbd->reset >= 0, HZ);
 
-       sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_SETLED);
-       sunkbd->serio->write(sunkbd->serio,
-               (!!test_bit(LED_CAPSL, sunkbd->dev->led) << 3) | (!!test_bit(LED_SCROLLL, sunkbd->dev->led) << 2) |
-               (!!test_bit(LED_COMPOSE, sunkbd->dev->led) << 1) | !!test_bit(LED_NUML, sunkbd->dev->led));
-       sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_NOCLICK - !!test_bit(SND_CLICK, sunkbd->dev->snd));
-       sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_BELLOFF - !!test_bit(SND_BELL, sunkbd->dev->snd));
+       serio_write(sunkbd->serio, SUNKBD_CMD_SETLED);
+       serio_write(sunkbd->serio,
+               (!!test_bit(LED_CAPSL,   sunkbd->dev->led) << 3) |
+               (!!test_bit(LED_SCROLLL, sunkbd->dev->led) << 2) |
+               (!!test_bit(LED_COMPOSE, sunkbd->dev->led) << 1) |
+                !!test_bit(LED_NUML,    sunkbd->dev->led));
+       serio_write(sunkbd->serio,
+               SUNKBD_CMD_NOCLICK - !!test_bit(SND_CLICK, sunkbd->dev->snd));
+       serio_write(sunkbd->serio,
+               SUNKBD_CMD_BELLOFF - !!test_bit(SND_BELL, sunkbd->dev->snd));
 }
 
-static void sunkbd_enable(struct sunkbd *sunkbd, int enable)
+static void sunkbd_enable(struct sunkbd *sunkbd, bool enable)
 {
        serio_pause_rx(sunkbd->serio);
        sunkbd->enabled = enable;
@@ -228,7 +246,8 @@ static void sunkbd_enable(struct sunkbd *sunkbd, int enable)
 }
 
 /*
- * sunkbd_connect() probes for a Sun keyboard and fills the necessary structures.
+ * sunkbd_connect() probes for a Sun keyboard and fills the necessary
+ * structures.
  */
 
 static int sunkbd_connect(struct serio *serio, struct serio_driver *drv)
@@ -260,7 +279,8 @@ static int sunkbd_connect(struct serio *serio, struct serio_driver *drv)
                goto fail3;
        }
 
-       snprintf(sunkbd->name, sizeof(sunkbd->name), "Sun Type %d keyboard", sunkbd->type);
+       snprintf(sunkbd->name, sizeof(sunkbd->name),
+                "Sun Type %d keyboard", sunkbd->type);
        memcpy(sunkbd->keycode, sunkbd_keycode, sizeof(sunkbd->keycode));
 
        input_dev->name = sunkbd->name;
@@ -284,11 +304,11 @@ static int sunkbd_connect(struct serio *serio, struct serio_driver *drv)
        input_dev->keycode = sunkbd->keycode;
        input_dev->keycodesize = sizeof(unsigned char);
        input_dev->keycodemax = ARRAY_SIZE(sunkbd_keycode);
-       for (i = 0; i < 128; i++)
-               set_bit(sunkbd->keycode[i], input_dev->keybit);
-       clear_bit(0, input_dev->keybit);
+       for (i = 0; i < ARRAY_SIZE(sunkbd_keycode); i++)
+               __set_bit(sunkbd->keycode[i], input_dev->keybit);
+       __clear_bit(KEY_RESERVED, input_dev->keybit);
 
-       sunkbd_enable(sunkbd, 1);
+       sunkbd_enable(sunkbd, true);
 
        err = input_register_device(sunkbd->dev);
        if (err)
@@ -296,7 +316,7 @@ static int sunkbd_connect(struct serio *serio, struct serio_driver *drv)
 
        return 0;
 
- fail4:        sunkbd_enable(sunkbd, 0);
+ fail4:        sunkbd_enable(sunkbd, false);
  fail3:        serio_close(serio);
  fail2:        serio_set_drvdata(serio, NULL);
  fail1:        input_free_device(input_dev);
@@ -312,7 +332,7 @@ static void sunkbd_disconnect(struct serio *serio)
 {
        struct sunkbd *sunkbd = serio_get_drvdata(serio);
 
-       sunkbd_enable(sunkbd, 0);
+       sunkbd_enable(sunkbd, false);
        input_unregister_device(sunkbd->dev);
        serio_close(serio);
        serio_set_drvdata(serio, NULL);
index 677276b1202029374eb283d202bba388d2ba9211..42cb3faf7336256ad8de736d7afcb2c4dc1e7756 100644 (file)
@@ -31,7 +31,7 @@
 #define KB_DISCHARGE_DELAY     10
 #define KB_ACTIVATE_DELAY      10
 
-static unsigned int tosakbd_keycode[NR_SCANCODES] = {
+static unsigned short tosakbd_keycode[NR_SCANCODES] = {
 0,
 0, KEY_W, 0, 0, 0, KEY_K, KEY_BACKSPACE, KEY_P,
 0, 0, 0, 0, 0, 0, 0, 0,
@@ -50,9 +50,9 @@ KEY_X, KEY_F, KEY_SPACE, KEY_APOSTROPHE, TOSA_KEY_MAIL, KEY_LEFT, KEY_DOWN, KEY_
 };
 
 struct tosakbd {
-       unsigned int keycode[ARRAY_SIZE(tosakbd_keycode)];
+       unsigned short keycode[ARRAY_SIZE(tosakbd_keycode)];
        struct input_dev *input;
-       int suspended;
+       bool suspended;
        spinlock_t lock; /* protect kbd scanning */
        struct timer_list timer;
 };
@@ -215,7 +215,7 @@ static int tosakbd_suspend(struct platform_device *dev, pm_message_t state)
        unsigned long flags;
 
        spin_lock_irqsave(&tosakbd->lock, flags);
-       tosakbd->suspended = 1;
+       tosakbd->suspended = true;
        spin_unlock_irqrestore(&tosakbd->lock, flags);
 
        del_timer_sync(&tosakbd->timer);
@@ -227,7 +227,7 @@ static int tosakbd_resume(struct platform_device *dev)
 {
        struct tosakbd *tosakbd = platform_get_drvdata(dev);
 
-       tosakbd->suspended = 0;
+       tosakbd->suspended = false;
        tosakbd_scankeyboard(dev);
 
        return 0;
@@ -277,14 +277,14 @@ static int __devinit tosakbd_probe(struct platform_device *pdev) {
 
        input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
        input_dev->keycode = tosakbd->keycode;
-       input_dev->keycodesize = sizeof(unsigned int);
+       input_dev->keycodesize = sizeof(tosakbd->keycode[0]);
        input_dev->keycodemax = ARRAY_SIZE(tosakbd_keycode);
 
        memcpy(tosakbd->keycode, tosakbd_keycode, sizeof(tosakbd_keycode));
 
        for (i = 0; i < ARRAY_SIZE(tosakbd_keycode); i++)
                __set_bit(tosakbd->keycode[i], input_dev->keybit);
-       clear_bit(0, input_dev->keybit);
+       __clear_bit(KEY_RESERVED, input_dev->keybit);
 
        /* Setup sense interrupts - RisingEdge Detect, sense lines as inputs */
        for (i = 0; i < TOSA_KEY_SENSE_NUM; i++) {
@@ -344,7 +344,7 @@ static int __devinit tosakbd_probe(struct platform_device *pdev) {
                                " direction for GPIO %d, error %d\n",
                                gpio, error);
                        gpio_free(gpio);
-                       goto fail;
+                       goto fail2;
                }
 
        }
@@ -353,7 +353,7 @@ static int __devinit tosakbd_probe(struct platform_device *pdev) {
        if (error) {
                printk(KERN_ERR "tosakbd: Unable to register input device, "
                        "error: %d\n", error);
-               goto fail;
+               goto fail2;
        }
 
        printk(KERN_INFO "input: Tosa Keyboard Registered\n");
diff --git a/drivers/input/keyboard/twl4030_keypad.c b/drivers/input/keyboard/twl4030_keypad.c
new file mode 100644 (file)
index 0000000..9a2977c
--- /dev/null
@@ -0,0 +1,480 @@
+/*
+ * twl4030_keypad.c - driver for 8x8 keypad controller in twl4030 chips
+ *
+ * Copyright (C) 2007 Texas Instruments, Inc.
+ * Copyright (C) 2008 Nokia Corporation
+ *
+ * Code re-written for 2430SDP by:
+ * Syed Mohammed Khasim <x0khasim@ti.com>
+ *
+ * Initial Code:
+ * Manjunatha G K <manjugk@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/input.h>
+#include <linux/platform_device.h>
+#include <linux/i2c/twl4030.h>
+
+
+/*
+ * The TWL4030 family chips include a keypad controller that supports
+ * up to an 8x8 switch matrix.  The controller can issue system wakeup
+ * events, since it uses only the always-on 32KiHz oscillator, and has
+ * an internal state machine that decodes pressed keys, including
+ * multi-key combinations.
+ *
+ * This driver lets boards define what keycodes they wish to report for
+ * which scancodes, as part of the "struct twl4030_keypad_data" used in
+ * the probe() routine.
+ *
+ * See the TPS65950 documentation; that's the general availability
+ * version of the TWL5030 second generation part.
+ */
+#define TWL4030_MAX_ROWS       8       /* TWL4030 hard limit */
+#define TWL4030_MAX_COLS       8
+#define TWL4030_ROW_SHIFT      3
+#define TWL4030_KEYMAP_SIZE    (TWL4030_MAX_ROWS * TWL4030_MAX_COLS)
+
+struct twl4030_keypad {
+       unsigned short  keymap[TWL4030_KEYMAP_SIZE];
+       u16             kp_state[TWL4030_MAX_ROWS];
+       unsigned        n_rows;
+       unsigned        n_cols;
+       unsigned        irq;
+
+       struct device *dbg_dev;
+       struct input_dev *input;
+};
+
+/*----------------------------------------------------------------------*/
+
+/* arbitrary prescaler value 0..7 */
+#define PTV_PRESCALER                  4
+
+/* Register Offsets */
+#define KEYP_CTRL                      0x00
+#define KEYP_DEB                       0x01
+#define KEYP_LONG_KEY                  0x02
+#define KEYP_LK_PTV                    0x03
+#define KEYP_TIMEOUT_L                 0x04
+#define KEYP_TIMEOUT_H                 0x05
+#define KEYP_KBC                       0x06
+#define KEYP_KBR                       0x07
+#define KEYP_SMS                       0x08
+#define KEYP_FULL_CODE_7_0             0x09    /* row 0 column status */
+#define KEYP_FULL_CODE_15_8            0x0a    /* ... row 1 ... */
+#define KEYP_FULL_CODE_23_16           0x0b
+#define KEYP_FULL_CODE_31_24           0x0c
+#define KEYP_FULL_CODE_39_32           0x0d
+#define KEYP_FULL_CODE_47_40           0x0e
+#define KEYP_FULL_CODE_55_48           0x0f
+#define KEYP_FULL_CODE_63_56           0x10
+#define KEYP_ISR1                      0x11
+#define KEYP_IMR1                      0x12
+#define KEYP_ISR2                      0x13
+#define KEYP_IMR2                      0x14
+#define KEYP_SIR                       0x15
+#define KEYP_EDR                       0x16    /* edge triggers */
+#define KEYP_SIH_CTRL                  0x17
+
+/* KEYP_CTRL_REG Fields */
+#define KEYP_CTRL_SOFT_NRST            BIT(0)
+#define KEYP_CTRL_SOFTMODEN            BIT(1)
+#define KEYP_CTRL_LK_EN                        BIT(2)
+#define KEYP_CTRL_TOE_EN               BIT(3)
+#define KEYP_CTRL_TOLE_EN              BIT(4)
+#define KEYP_CTRL_RP_EN                        BIT(5)
+#define KEYP_CTRL_KBD_ON               BIT(6)
+
+/* KEYP_DEB, KEYP_LONG_KEY, KEYP_TIMEOUT_x*/
+#define KEYP_PERIOD_US(t, prescale)    ((t) / (31 << (prescale + 1)) - 1)
+
+/* KEYP_LK_PTV_REG Fields */
+#define KEYP_LK_PTV_PTV_SHIFT          5
+
+/* KEYP_{IMR,ISR,SIR} Fields */
+#define KEYP_IMR1_MIS                  BIT(3)
+#define KEYP_IMR1_TO                   BIT(2)
+#define KEYP_IMR1_LK                   BIT(1)
+#define KEYP_IMR1_KP                   BIT(0)
+
+/* KEYP_EDR Fields */
+#define KEYP_EDR_KP_FALLING            0x01
+#define KEYP_EDR_KP_RISING             0x02
+#define KEYP_EDR_KP_BOTH               0x03
+#define KEYP_EDR_LK_FALLING            0x04
+#define KEYP_EDR_LK_RISING             0x08
+#define KEYP_EDR_TO_FALLING            0x10
+#define KEYP_EDR_TO_RISING             0x20
+#define KEYP_EDR_MIS_FALLING           0x40
+#define KEYP_EDR_MIS_RISING            0x80
+
+
+/*----------------------------------------------------------------------*/
+
+static int twl4030_kpread(struct twl4030_keypad *kp,
+               u8 *data, u32 reg, u8 num_bytes)
+{
+       int ret = twl4030_i2c_read(TWL4030_MODULE_KEYPAD, data, reg, num_bytes);
+
+       if (ret < 0)
+               dev_warn(kp->dbg_dev,
+                       "Couldn't read TWL4030: %X - ret %d[%x]\n",
+                        reg, ret, ret);
+
+       return ret;
+}
+
+static int twl4030_kpwrite_u8(struct twl4030_keypad *kp, u8 data, u32 reg)
+{
+       int ret = twl4030_i2c_write_u8(TWL4030_MODULE_KEYPAD, data, reg);
+
+       if (ret < 0)
+               dev_warn(kp->dbg_dev,
+                       "Could not write TWL4030: %X - ret %d[%x]\n",
+                        reg, ret, ret);
+
+       return ret;
+}
+
+static inline u16 twl4030_col_xlate(struct twl4030_keypad *kp, u8 col)
+{
+       /* If all bits in a row are active for all coloumns then
+        * we have that row line connected to gnd. Mark this
+        * key on as if it was on matrix position n_cols (ie
+        * one higher than the size of the matrix).
+        */
+       if (col == 0xFF)
+               return 1 << kp->n_cols;
+       else
+               return col & ((1 << kp->n_cols) - 1);
+}
+
+static int twl4030_read_kp_matrix_state(struct twl4030_keypad *kp, u16 *state)
+{
+       u8 new_state[TWL4030_MAX_ROWS];
+       int row;
+       int ret = twl4030_kpread(kp, new_state,
+                                KEYP_FULL_CODE_7_0, kp->n_rows);
+       if (ret >= 0)
+               for (row = 0; row < kp->n_rows; row++)
+                       state[row] = twl4030_col_xlate(kp, new_state[row]);
+
+       return ret;
+}
+
+static int twl4030_is_in_ghost_state(struct twl4030_keypad *kp, u16 *key_state)
+{
+       int i;
+       u16 check = 0;
+
+       for (i = 0; i < kp->n_rows; i++) {
+               u16 col = key_state[i];
+
+               if ((col & check) && hweight16(col) > 1)
+                       return 1;
+
+               check |= col;
+       }
+
+       return 0;
+}
+
+static void twl4030_kp_scan(struct twl4030_keypad *kp, bool release_all)
+{
+       struct input_dev *input = kp->input;
+       u16 new_state[TWL4030_MAX_ROWS];
+       int col, row;
+
+       if (release_all)
+               memset(new_state, 0, sizeof(new_state));
+       else {
+               /* check for any changes */
+               int ret = twl4030_read_kp_matrix_state(kp, new_state);
+
+               if (ret < 0)    /* panic ... */
+                       return;
+
+               if (twl4030_is_in_ghost_state(kp, new_state))
+                       return;
+       }
+
+       /* check for changes and print those */
+       for (row = 0; row < kp->n_rows; row++) {
+               int changed = new_state[row] ^ kp->kp_state[row];
+
+               if (!changed)
+                       continue;
+
+               for (col = 0; col < kp->n_cols; col++) {
+                       int code;
+
+                       if (!(changed & (1 << col)))
+                               continue;
+
+                       dev_dbg(kp->dbg_dev, "key [%d:%d] %s\n", row, col,
+                               (new_state[row] & (1 << col)) ?
+                               "press" : "release");
+
+                       code = MATRIX_SCAN_CODE(row, col, TWL4030_ROW_SHIFT);
+                       input_event(input, EV_MSC, MSC_SCAN, code);
+                       input_report_key(input, kp->keymap[code],
+                                        new_state[row] & (1 << col));
+               }
+               kp->kp_state[row] = new_state[row];
+       }
+       input_sync(input);
+}
+
+/*
+ * Keypad interrupt handler
+ */
+static irqreturn_t do_kp_irq(int irq, void *_kp)
+{
+       struct twl4030_keypad *kp = _kp;
+       u8 reg;
+       int ret;
+
+#ifdef CONFIG_LOCKDEP
+       /* WORKAROUND for lockdep forcing IRQF_DISABLED on us, which
+        * we don't want and can't tolerate.  Although it might be
+        * friendlier not to borrow this thread context...
+        */
+       local_irq_enable();
+#endif
+
+       /* Read & Clear TWL4030 pending interrupt */
+       ret = twl4030_kpread(kp, &reg, KEYP_ISR1, 1);
+
+       /* Release all keys if I2C has gone bad or
+        * the KEYP has gone to idle state */
+       if (ret >= 0 && (reg & KEYP_IMR1_KP))
+               twl4030_kp_scan(kp, false);
+       else
+               twl4030_kp_scan(kp, true);
+
+       return IRQ_HANDLED;
+}
+
+static int __devinit twl4030_kp_program(struct twl4030_keypad *kp)
+{
+       u8 reg;
+       int i;
+
+       /* Enable controller, with hardware decoding but not autorepeat */
+       reg = KEYP_CTRL_SOFT_NRST | KEYP_CTRL_SOFTMODEN
+               | KEYP_CTRL_TOE_EN | KEYP_CTRL_KBD_ON;
+       if (twl4030_kpwrite_u8(kp, reg, KEYP_CTRL) < 0)
+               return -EIO;
+
+       /* NOTE:  we could use sih_setup() here to package keypad
+        * event sources as four different IRQs ... but we don't.
+        */
+
+       /* Enable TO rising and KP rising and falling edge detection */
+       reg = KEYP_EDR_KP_BOTH | KEYP_EDR_TO_RISING;
+       if (twl4030_kpwrite_u8(kp, reg, KEYP_EDR) < 0)
+               return -EIO;
+
+       /* Set PTV prescaler Field */
+       reg = (PTV_PRESCALER << KEYP_LK_PTV_PTV_SHIFT);
+       if (twl4030_kpwrite_u8(kp, reg, KEYP_LK_PTV) < 0)
+               return -EIO;
+
+       /* Set key debounce time to 20 ms */
+       i = KEYP_PERIOD_US(20000, PTV_PRESCALER);
+       if (twl4030_kpwrite_u8(kp, i, KEYP_DEB) < 0)
+               return -EIO;
+
+       /* Set timeout period to 100 ms */
+       i = KEYP_PERIOD_US(200000, PTV_PRESCALER);
+       if (twl4030_kpwrite_u8(kp, (i & 0xFF), KEYP_TIMEOUT_L) < 0)
+               return -EIO;
+
+       if (twl4030_kpwrite_u8(kp, (i >> 8), KEYP_TIMEOUT_H) < 0)
+               return -EIO;
+
+       /*
+        * Enable Clear-on-Read; disable remembering events that fire
+        * after the IRQ but before our handler acks (reads) them,
+        */
+       reg = TWL4030_SIH_CTRL_COR_MASK | TWL4030_SIH_CTRL_PENDDIS_MASK;
+       if (twl4030_kpwrite_u8(kp, reg, KEYP_SIH_CTRL) < 0)
+               return -EIO;
+
+       /* initialize key state; irqs update it from here on */
+       if (twl4030_read_kp_matrix_state(kp, kp->kp_state) < 0)
+               return -EIO;
+
+       return 0;
+}
+
+/*
+ * Registers keypad device with input subsystem
+ * and configures TWL4030 keypad registers
+ */
+static int __devinit twl4030_kp_probe(struct platform_device *pdev)
+{
+       struct twl4030_keypad_data *pdata = pdev->dev.platform_data;
+       const struct matrix_keymap_data *keymap_data = pdata->keymap_data;
+       struct twl4030_keypad *kp;
+       struct input_dev *input;
+       u8 reg;
+       int error;
+
+       if (!pdata || !pdata->rows || !pdata->cols ||
+           pdata->rows > TWL4030_MAX_ROWS || pdata->cols > TWL4030_MAX_COLS) {
+               dev_err(&pdev->dev, "Invalid platform_data\n");
+               return -EINVAL;
+       }
+
+       kp = kzalloc(sizeof(*kp), GFP_KERNEL);
+       input = input_allocate_device();
+       if (!kp || !input) {
+               error = -ENOMEM;
+               goto err1;
+       }
+
+       /* Get the debug Device */
+       kp->dbg_dev = &pdev->dev;
+       kp->input = input;
+
+       kp->n_rows = pdata->rows;
+       kp->n_cols = pdata->cols;
+       kp->irq = platform_get_irq(pdev, 0);
+
+       /* setup input device */
+       __set_bit(EV_KEY, input->evbit);
+
+       /* Enable auto repeat feature of Linux input subsystem */
+       if (pdata->rep)
+               __set_bit(EV_REP, input->evbit);
+
+       input_set_capability(input, EV_MSC, MSC_SCAN);
+
+       input->name             = "TWL4030 Keypad";
+       input->phys             = "twl4030_keypad/input0";
+       input->dev.parent       = &pdev->dev;
+
+       input->id.bustype       = BUS_HOST;
+       input->id.vendor        = 0x0001;
+       input->id.product       = 0x0001;
+       input->id.version       = 0x0003;
+
+       input->keycode          = kp->keymap;
+       input->keycodesize      = sizeof(kp->keymap[0]);
+       input->keycodemax       = ARRAY_SIZE(kp->keymap);
+
+       matrix_keypad_build_keymap(keymap_data, TWL4030_ROW_SHIFT,
+                                  input->keycode, input->keybit);
+
+       error = input_register_device(input);
+       if (error) {
+               dev_err(kp->dbg_dev,
+                       "Unable to register twl4030 keypad device\n");
+               goto err1;
+       }
+
+       error = twl4030_kp_program(kp);
+       if (error)
+               goto err2;
+
+       /*
+        * This ISR will always execute in kernel thread context because of
+        * the need to access the TWL4030 over the I2C bus.
+        *
+        * NOTE:  we assume this host is wired to TWL4040 INT1, not INT2 ...
+        */
+       error = request_irq(kp->irq, do_kp_irq, 0, pdev->name, kp);
+       if (error) {
+               dev_info(kp->dbg_dev, "request_irq failed for irq no=%d\n",
+                       kp->irq);
+               goto err3;
+       }
+
+       /* Enable KP and TO interrupts now. */
+       reg = (u8) ~(KEYP_IMR1_KP | KEYP_IMR1_TO);
+       if (twl4030_kpwrite_u8(kp, reg, KEYP_IMR1)) {
+               error = -EIO;
+               goto err4;
+       }
+
+       platform_set_drvdata(pdev, kp);
+       return 0;
+
+err4:
+       /* mask all events - we don't care about the result */
+       (void) twl4030_kpwrite_u8(kp, 0xff, KEYP_IMR1);
+err3:
+       free_irq(kp->irq, NULL);
+err2:
+       input_unregister_device(input);
+       input = NULL;
+err1:
+       input_free_device(input);
+       kfree(kp);
+       return error;
+}
+
+static int __devexit twl4030_kp_remove(struct platform_device *pdev)
+{
+       struct twl4030_keypad *kp = platform_get_drvdata(pdev);
+
+       free_irq(kp->irq, kp);
+       input_unregister_device(kp->input);
+       platform_set_drvdata(pdev, NULL);
+       kfree(kp);
+
+       return 0;
+}
+
+/*
+ * NOTE: twl4030 are multi-function devices connected via I2C.
+ * So this device is a child of an I2C parent, thus it needs to
+ * support unplug/replug (which most platform devices don't).
+ */
+
+static struct platform_driver twl4030_kp_driver = {
+       .probe          = twl4030_kp_probe,
+       .remove         = __devexit_p(twl4030_kp_remove),
+       .driver         = {
+               .name   = "twl4030_keypad",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init twl4030_kp_init(void)
+{
+       return platform_driver_register(&twl4030_kp_driver);
+}
+module_init(twl4030_kp_init);
+
+static void __exit twl4030_kp_exit(void)
+{
+       platform_driver_unregister(&twl4030_kp_driver);
+}
+module_exit(twl4030_kp_exit);
+
+MODULE_AUTHOR("Texas Instruments");
+MODULE_DESCRIPTION("TWL4030 Keypad Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:twl4030_keypad");
+
diff --git a/drivers/input/keyboard/w90p910_keypad.c b/drivers/input/keyboard/w90p910_keypad.c
new file mode 100644 (file)
index 0000000..6032def
--- /dev/null
@@ -0,0 +1,281 @@
+/*
+ * Copyright (c) 2008-2009 Nuvoton technology corporation.
+ *
+ * Wan ZongShun <mcuos.com@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation;version 2 of the License.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/input.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+
+#include <mach/w90p910_keypad.h>
+
+/* Keypad Interface Control Registers */
+#define KPI_CONF               0x00
+#define KPI_3KCONF             0x04
+#define KPI_LPCONF             0x08
+#define KPI_STATUS             0x0C
+
+#define IS1KEY                 (0x01 << 16)
+#define INTTR                  (0x01 << 21)
+#define KEY0R                  (0x0f << 3)
+#define KEY0C                  0x07
+#define DEBOUNCE_BIT           0x08
+#define KSIZE0                 (0x01 << 16)
+#define KSIZE1                 (0x01 << 17)
+#define KPSEL                  (0x01 << 19)
+#define ENKP                   (0x01 << 18)
+
+#define KGET_RAW(n)            (((n) & KEY0R) >> 3)
+#define KGET_COLUMN(n)         ((n) & KEY0C)
+
+#define W90P910_MAX_KEY_NUM    (8 * 8)
+#define W90P910_ROW_SHIFT      3
+
+struct w90p910_keypad {
+       const struct w90p910_keypad_platform_data *pdata;
+       struct clk *clk;
+       struct input_dev *input_dev;
+       void __iomem *mmio_base;
+       int irq;
+       unsigned short keymap[W90P910_MAX_KEY_NUM];
+};
+
+static void w90p910_keypad_scan_matrix(struct w90p910_keypad *keypad,
+                                                       unsigned int status)
+{
+       struct input_dev *input_dev = keypad->input_dev;
+       unsigned int row = KGET_RAW(status);
+       unsigned int col = KGET_COLUMN(status);
+       unsigned int code = MATRIX_SCAN_CODE(row, col, W90P910_ROW_SHIFT);
+       unsigned int key = keypad->keymap[code];
+
+       input_event(input_dev, EV_MSC, MSC_SCAN, code);
+       input_report_key(input_dev, key, 1);
+       input_sync(input_dev);
+
+       input_event(input_dev, EV_MSC, MSC_SCAN, code);
+       input_report_key(input_dev, key, 0);
+       input_sync(input_dev);
+}
+
+static irqreturn_t w90p910_keypad_irq_handler(int irq, void *dev_id)
+{
+       struct w90p910_keypad *keypad = dev_id;
+       unsigned int  kstatus, val;
+
+       kstatus = __raw_readl(keypad->mmio_base + KPI_STATUS);
+
+       val = INTTR | IS1KEY;
+
+       if (kstatus & val)
+               w90p910_keypad_scan_matrix(keypad, kstatus);
+
+       return IRQ_HANDLED;
+}
+
+static int w90p910_keypad_open(struct input_dev *dev)
+{
+       struct w90p910_keypad *keypad = input_get_drvdata(dev);
+       const struct w90p910_keypad_platform_data *pdata = keypad->pdata;
+       unsigned int val, config;
+
+       /* Enable unit clock */
+       clk_enable(keypad->clk);
+
+       val = __raw_readl(keypad->mmio_base + KPI_CONF);
+       val |= (KPSEL | ENKP);
+       val &= ~(KSIZE0 | KSIZE1);
+
+       config = pdata->prescale | (pdata->debounce << DEBOUNCE_BIT);
+
+       val |= config;
+
+       __raw_writel(val, keypad->mmio_base + KPI_CONF);
+
+       return 0;
+}
+
+static void w90p910_keypad_close(struct input_dev *dev)
+{
+       struct w90p910_keypad *keypad = input_get_drvdata(dev);
+
+       /* Disable clock unit */
+       clk_disable(keypad->clk);
+}
+
+static int __devinit w90p910_keypad_probe(struct platform_device *pdev)
+{
+       const struct w90p910_keypad_platform_data *pdata =
+                                               pdev->dev.platform_data;
+       const struct matrix_keymap_data *keymap_data;
+       struct w90p910_keypad *keypad;
+       struct input_dev *input_dev;
+       struct resource *res;
+       int irq;
+       int error;
+
+       if (!pdata) {
+               dev_err(&pdev->dev, "no platform data defined\n");
+               return -EINVAL;
+       }
+
+       keymap_data = pdata->keymap_data;
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0) {
+               dev_err(&pdev->dev, "failed to get keypad irq\n");
+               return -ENXIO;
+       }
+
+       keypad = kzalloc(sizeof(struct w90p910_keypad), GFP_KERNEL);
+       input_dev = input_allocate_device();
+       if (!keypad || !input_dev) {
+               dev_err(&pdev->dev, "failed to allocate driver data\n");
+               error = -ENOMEM;
+               goto failed_free;
+       }
+
+       keypad->pdata = pdata;
+       keypad->input_dev = input_dev;
+       keypad->irq = irq;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (res == NULL) {
+               dev_err(&pdev->dev, "failed to get I/O memory\n");
+               error = -ENXIO;
+               goto failed_free;
+       }
+
+       res = request_mem_region(res->start, resource_size(res), pdev->name);
+       if (res == NULL) {
+               dev_err(&pdev->dev, "failed to request I/O memory\n");
+               error = -EBUSY;
+               goto failed_free;
+       }
+
+       keypad->mmio_base = ioremap(res->start, resource_size(res));
+       if (keypad->mmio_base == NULL) {
+               dev_err(&pdev->dev, "failed to remap I/O memory\n");
+               error = -ENXIO;
+               goto failed_free_res;
+       }
+
+       keypad->clk = clk_get(&pdev->dev, NULL);
+       if (IS_ERR(keypad->clk)) {
+               dev_err(&pdev->dev, "failed to get keypad clock\n");
+               error = PTR_ERR(keypad->clk);
+               goto failed_free_io;
+       }
+
+       /* set multi-function pin for w90p910 kpi. */
+       mfp_set_groupi(&pdev->dev);
+
+       input_dev->name = pdev->name;
+       input_dev->id.bustype = BUS_HOST;
+       input_dev->open = w90p910_keypad_open;
+       input_dev->close = w90p910_keypad_close;
+       input_dev->dev.parent = &pdev->dev;
+
+       input_dev->keycode = keypad->keymap;
+       input_dev->keycodesize = sizeof(keypad->keymap[0]);
+       input_dev->keycodemax = ARRAY_SIZE(keypad->keymap);
+
+       input_set_drvdata(input_dev, keypad);
+
+       input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
+       input_set_capability(input_dev, EV_MSC, MSC_SCAN);
+
+       matrix_keypad_build_keymap(keymap_data, W90P910_ROW_SHIFT,
+                                  input_dev->keycode, input_dev->keybit);
+
+       error = request_irq(keypad->irq, w90p910_keypad_irq_handler,
+                           IRQF_DISABLED, pdev->name, keypad);
+       if (error) {
+               dev_err(&pdev->dev, "failed to request IRQ\n");
+               goto failed_put_clk;
+       }
+
+       /* Register the input device */
+       error = input_register_device(input_dev);
+       if (error) {
+               dev_err(&pdev->dev, "failed to register input device\n");
+               goto failed_free_irq;
+       }
+
+       platform_set_drvdata(pdev, keypad);
+       return 0;
+
+failed_free_irq:
+       free_irq(irq, pdev);
+failed_put_clk:
+       clk_put(keypad->clk);
+failed_free_io:
+       iounmap(keypad->mmio_base);
+failed_free_res:
+       release_mem_region(res->start, resource_size(res));
+failed_free:
+       input_free_device(input_dev);
+       kfree(keypad);
+       return error;
+}
+
+static int __devexit w90p910_keypad_remove(struct platform_device *pdev)
+{
+       struct w90p910_keypad *keypad = platform_get_drvdata(pdev);
+       struct resource *res;
+
+       free_irq(keypad->irq, pdev);
+
+       clk_put(keypad->clk);
+
+       input_unregister_device(keypad->input_dev);
+
+       iounmap(keypad->mmio_base);
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       release_mem_region(res->start, resource_size(res));
+
+       platform_set_drvdata(pdev, NULL);
+       kfree(keypad);
+
+       return 0;
+}
+
+static struct platform_driver w90p910_keypad_driver = {
+       .probe          = w90p910_keypad_probe,
+       .remove         = __devexit_p(w90p910_keypad_remove),
+       .driver         = {
+               .name   = "nuc900-keypad",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init w90p910_keypad_init(void)
+{
+       return platform_driver_register(&w90p910_keypad_driver);
+}
+
+static void __exit w90p910_keypad_exit(void)
+{
+       platform_driver_unregister(&w90p910_keypad_driver);
+}
+
+module_init(w90p910_keypad_init);
+module_exit(w90p910_keypad_exit);
+
+MODULE_AUTHOR("Wan ZongShun <mcuos.com@gmail.com>");
+MODULE_DESCRIPTION("w90p910 keypad driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:nuc900-keypad");
index 1acfa3a05aad50ced8ab8febf413987aafade9ac..cbe21bc96b52a2ab09f434192107224e954a1291 100644 (file)
@@ -269,4 +269,14 @@ config INPUT_DM355EVM
 
          To compile this driver as a module, choose M here: the
          module will be called dm355evm_keys.
+
+config INPUT_BFIN_ROTARY
+       tristate "Blackfin Rotary support"
+       depends on BF54x || BF52x
+       help
+         Say Y here if you want to use the Blackfin Rotary.
+
+         To compile this driver as a module, choose M here: the
+         module will be called bfin-rotary.
+
 endif
index 0d979fd4cd575681caabce113afd19a07e85c497..79c1e9a5ea317c1f5b25978ffb7422fa8019c40b 100644 (file)
@@ -8,6 +8,7 @@ obj-$(CONFIG_INPUT_APANEL)              += apanel.o
 obj-$(CONFIG_INPUT_ATI_REMOTE)         += ati_remote.o
 obj-$(CONFIG_INPUT_ATI_REMOTE2)                += ati_remote2.o
 obj-$(CONFIG_INPUT_ATLAS_BTNS)         += atlas_btns.o
+obj-$(CONFIG_INPUT_BFIN_ROTARY)                += bfin_rotary.o
 obj-$(CONFIG_INPUT_CM109)              += cm109.o
 obj-$(CONFIG_INPUT_COBALT_BTNS)                += cobalt_btns.o
 obj-$(CONFIG_INPUT_DM355EVM)           += dm355evm_keys.o
diff --git a/drivers/input/misc/bfin_rotary.c b/drivers/input/misc/bfin_rotary.c
new file mode 100644 (file)
index 0000000..690f3fa
--- /dev/null
@@ -0,0 +1,283 @@
+/*
+ * Rotary counter driver for Analog Devices Blackfin Processors
+ *
+ * Copyright 2008-2009 Analog Devices Inc.
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/pm.h>
+#include <linux/platform_device.h>
+#include <linux/input.h>
+
+#include <asm/portmux.h>
+#include <asm/bfin_rotary.h>
+
+static const u16 per_cnt[] = {
+       P_CNT_CUD,
+       P_CNT_CDG,
+       P_CNT_CZM,
+       0
+};
+
+struct bfin_rot {
+       struct input_dev *input;
+       int irq;
+       unsigned int up_key;
+       unsigned int down_key;
+       unsigned int button_key;
+       unsigned int rel_code;
+       unsigned short cnt_config;
+       unsigned short cnt_imask;
+       unsigned short cnt_debounce;
+};
+
+static void report_key_event(struct input_dev *input, int keycode)
+{
+       /* simulate a press-n-release */
+       input_report_key(input, keycode, 1);
+       input_sync(input);
+       input_report_key(input, keycode, 0);
+       input_sync(input);
+}
+
+static void report_rotary_event(struct bfin_rot *rotary, int delta)
+{
+       struct input_dev *input = rotary->input;
+
+       if (rotary->up_key) {
+               report_key_event(input,
+                                delta > 0 ? rotary->up_key : rotary->down_key);
+       } else {
+               input_report_rel(input, rotary->rel_code, delta);
+               input_sync(input);
+       }
+}
+
+static irqreturn_t bfin_rotary_isr(int irq, void *dev_id)
+{
+       struct platform_device *pdev = dev_id;
+       struct bfin_rot *rotary = platform_get_drvdata(pdev);
+       int delta;
+
+       switch (bfin_read_CNT_STATUS()) {
+
+       case ICII:
+               break;
+
+       case UCII:
+       case DCII:
+               delta = bfin_read_CNT_COUNTER();
+               if (delta)
+                       report_rotary_event(rotary, delta);
+               break;
+
+       case CZMII:
+               report_key_event(rotary->input, rotary->button_key);
+               break;
+
+       default:
+               break;
+       }
+
+       bfin_write_CNT_COMMAND(W1LCNT_ZERO);    /* Clear COUNTER */
+       bfin_write_CNT_STATUS(-1);      /* Clear STATUS */
+
+       return IRQ_HANDLED;
+}
+
+static int __devinit bfin_rotary_probe(struct platform_device *pdev)
+{
+       struct bfin_rotary_platform_data *pdata = pdev->dev.platform_data;
+       struct bfin_rot *rotary;
+       struct input_dev *input;
+       int error;
+
+       /* Basic validation */
+       if ((pdata->rotary_up_key && !pdata->rotary_down_key) ||
+           (!pdata->rotary_up_key && pdata->rotary_down_key)) {
+               return -EINVAL;
+       }
+
+       error = peripheral_request_list(per_cnt, dev_name(&pdev->dev));
+       if (error) {
+               dev_err(&pdev->dev, "requesting peripherals failed\n");
+               return error;
+       }
+
+       rotary = kzalloc(sizeof(struct bfin_rot), GFP_KERNEL);
+       input = input_allocate_device();
+       if (!rotary || !input) {
+               error = -ENOMEM;
+               goto out1;
+       }
+
+       rotary->input = input;
+
+       rotary->up_key = pdata->rotary_up_key;
+       rotary->down_key = pdata->rotary_down_key;
+       rotary->button_key = pdata->rotary_button_key;
+       rotary->rel_code = pdata->rotary_rel_code;
+
+       error = rotary->irq = platform_get_irq(pdev, 0);
+       if (error < 0)
+               goto out1;
+
+       input->name = pdev->name;
+       input->phys = "bfin-rotary/input0";
+       input->dev.parent = &pdev->dev;
+
+       input_set_drvdata(input, rotary);
+
+       input->id.bustype = BUS_HOST;
+       input->id.vendor = 0x0001;
+       input->id.product = 0x0001;
+       input->id.version = 0x0100;
+
+       if (rotary->up_key) {
+               __set_bit(EV_KEY, input->evbit);
+               __set_bit(rotary->up_key, input->keybit);
+               __set_bit(rotary->down_key, input->keybit);
+       } else {
+               __set_bit(EV_REL, input->evbit);
+               __set_bit(rotary->rel_code, input->relbit);
+       }
+
+       if (rotary->button_key) {
+               __set_bit(EV_KEY, input->evbit);
+               __set_bit(rotary->button_key, input->keybit);
+       }
+
+       error = request_irq(rotary->irq, bfin_rotary_isr,
+                           0, dev_name(&pdev->dev), pdev);
+       if (error) {
+               dev_err(&pdev->dev,
+                       "unable to claim irq %d; error %d\n",
+                       rotary->irq, error);
+               goto out1;
+       }
+
+       error = input_register_device(input);
+       if (error) {
+               dev_err(&pdev->dev,
+                       "unable to register input device (%d)\n", error);
+               goto out2;
+       }
+
+       if (pdata->rotary_button_key)
+               bfin_write_CNT_IMASK(CZMIE);
+
+       if (pdata->mode & ROT_DEBE)
+               bfin_write_CNT_DEBOUNCE(pdata->debounce & DPRESCALE);
+
+       if (pdata->mode)
+               bfin_write_CNT_CONFIG(bfin_read_CNT_CONFIG() |
+                                       (pdata->mode & ~CNTE));
+
+       bfin_write_CNT_IMASK(bfin_read_CNT_IMASK() | UCIE | DCIE);
+       bfin_write_CNT_CONFIG(bfin_read_CNT_CONFIG() | CNTE);
+
+       platform_set_drvdata(pdev, rotary);
+       device_init_wakeup(&pdev->dev, 1);
+
+       return 0;
+
+out2:
+       free_irq(rotary->irq, pdev);
+out1:
+       input_free_device(input);
+       kfree(rotary);
+       peripheral_free_list(per_cnt);
+
+       return error;
+}
+
+static int __devexit bfin_rotary_remove(struct platform_device *pdev)
+{
+       struct bfin_rot *rotary = platform_get_drvdata(pdev);
+
+       bfin_write_CNT_CONFIG(0);
+       bfin_write_CNT_IMASK(0);
+
+       free_irq(rotary->irq, pdev);
+       input_unregister_device(rotary->input);
+       peripheral_free_list(per_cnt);
+
+       kfree(rotary);
+       platform_set_drvdata(pdev, NULL);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int bfin_rotary_suspend(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct bfin_rot *rotary = platform_get_drvdata(pdev);
+
+       rotary->cnt_config = bfin_read_CNT_CONFIG();
+       rotary->cnt_imask = bfin_read_CNT_IMASK();
+       rotary->cnt_debounce = bfin_read_CNT_DEBOUNCE();
+
+       if (device_may_wakeup(&pdev->dev))
+               enable_irq_wake(rotary->irq);
+
+       return 0;
+}
+
+static int bfin_rotary_resume(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct bfin_rot *rotary = platform_get_drvdata(pdev);
+
+       bfin_write_CNT_DEBOUNCE(rotary->cnt_debounce);
+       bfin_write_CNT_IMASK(rotary->cnt_imask);
+       bfin_write_CNT_CONFIG(rotary->cnt_config & ~CNTE);
+
+       if (device_may_wakeup(&pdev->dev))
+               disable_irq_wake(rotary->irq);
+
+       if (rotary->cnt_config & CNTE)
+               bfin_write_CNT_CONFIG(rotary->cnt_config);
+
+       return 0;
+}
+
+static struct dev_pm_ops bfin_rotary_pm_ops = {
+       .suspend        = bfin_rotary_suspend,
+       .resume         = bfin_rotary_resume,
+};
+#endif
+
+static struct platform_driver bfin_rotary_device_driver = {
+       .probe          = bfin_rotary_probe,
+       .remove         = __devexit_p(bfin_rotary_remove),
+       .driver         = {
+               .name   = "bfin-rotary",
+               .owner  = THIS_MODULE,
+#ifdef CONFIG_PM
+               .pm     = &bfin_rotary_pm_ops,
+#endif
+       },
+};
+
+static int __init bfin_rotary_init(void)
+{
+       return platform_driver_register(&bfin_rotary_device_driver);
+}
+module_init(bfin_rotary_init);
+
+static void __exit bfin_rotary_exit(void)
+{
+       platform_driver_unregister(&bfin_rotary_device_driver);
+}
+module_exit(bfin_rotary_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_DESCRIPTION("Rotary Counter driver for Blackfin Processors");
+MODULE_ALIAS("platform:bfin-rotary");
index d114d3a9e1e94b7129870642943d7ac91a368cac..ee73d7219c9280c6be1a3e3c7b4c82d6ef4a0b72 100644 (file)
@@ -116,7 +116,7 @@ static int __devinit cobalt_buttons_probe(struct platform_device *pdev)
        }
 
        bdev->poll_dev = poll_dev;
-       bdev->reg = ioremap(res->start, res->end - res->start + 1);
+       bdev->reg = ioremap(res->start, resource_size(res));
        dev_set_drvdata(&pdev->dev, bdev);
 
        error = input_register_polled_device(poll_dev);
index a63315ce4a6c7920eccb559867725f60334592bb..0918acae584ac9844d2dd64c500f235b56f22b72 100644 (file)
  * pressed, or its autorepeat kicks in, an event is sent.  This driver
  * read those events from the small (32 event) queue and reports them.
  *
- * Because we communicate with the MSP430 using I2C, and all I2C calls
- * in Linux sleep, we need to cons up a kind of threaded IRQ handler
- * using a work_struct.  The IRQ is active low, but we use it through
- * the GPIO controller so we can trigger on falling edges.
- *
  * Note that physically there can only be one of these devices.
  *
  * This driver was tested with firmware revision A4.
  */
 struct dm355evm_keys {
-       struct work_struct      work;
        struct input_dev        *input;
        struct device           *dev;
        int                     irq;
 };
 
-static irqreturn_t dm355evm_keys_irq(int irq, void *_keys)
-{
-       struct dm355evm_keys    *keys = _keys;
-
-       schedule_work(&keys->work);
-       return IRQ_HANDLED;
-}
-
 /* These initial keycodes can be remapped by dm355evm_setkeycode(). */
 static struct {
        u16     event;
@@ -110,13 +96,12 @@ static struct {
        { 0x3169, KEY_PAUSE, },
 };
 
-static void dm355evm_keys_work(struct work_struct *work)
+/* runs in an IRQ thread -- can (and will!) sleep */
+static irqreturn_t dm355evm_keys_irq(int irq, void *_keys)
 {
-       struct dm355evm_keys    *keys;
+       struct dm355evm_keys    *keys = _keys;
        int                     status;
 
-       keys = container_of(work, struct dm355evm_keys, work);
-
        /* For simplicity we ignore INPUT_COUNT and just read
         * events until we get the "queue empty" indicator.
         * Reading INPUT_LOW decrements the count.
@@ -183,6 +168,19 @@ static void dm355evm_keys_work(struct work_struct *work)
                input_report_key(keys->input, keycode, 0);
                input_sync(keys->input);
        }
+       return IRQ_HANDLED;
+}
+
+/*
+ * Because we communicate with the MSP430 using I2C, and all I2C calls
+ * in Linux sleep, we use a threaded IRQ handler.  The IRQ itself is
+ * active low, but we go through the GPIO controller so we can trigger
+ * on falling edges and not worry about enabling/disabling the IRQ in
+ * the keypress handling path.
+ */
+static irqreturn_t dm355evm_keys_hardirq(int irq, void *_keys)
+{
+       return IRQ_WAKE_THREAD;
 }
 
 static int dm355evm_setkeycode(struct input_dev *dev, int index, int keycode)
@@ -233,7 +231,6 @@ static int __devinit dm355evm_keys_probe(struct platform_device *pdev)
 
        keys->dev = &pdev->dev;
        keys->input = input;
-       INIT_WORK(&keys->work, dm355evm_keys_work);
 
        /* set up "threaded IRQ handler" */
        status = platform_get_irq(pdev, 0);
@@ -260,9 +257,10 @@ static int __devinit dm355evm_keys_probe(struct platform_device *pdev)
 
        /* REVISIT:  flush the event queue? */
 
-       status = request_irq(keys->irq, dm355evm_keys_irq,
-                            IRQF_TRIGGER_FALLING,
-                            dev_name(&pdev->dev), keys);
+       status = request_threaded_irq(keys->irq,
+                       dm355evm_keys_hardirq, dm355evm_keys_irq,
+                       IRQF_TRIGGER_FALLING,
+                       dev_name(&pdev->dev), keys);
        if (status < 0)
                goto fail1;
 
index 27ee976eb54cea4e561fd32665ccfa539d244b96..11fd038a078f2121367e0b80f16dcc54fcd94ea1 100644 (file)
@@ -243,9 +243,9 @@ enum { KE_END, KE_KEY, KE_SW, KE_WIFI, KE_BLUETOOTH };
 #define FE_UNTESTED 0x80
 
 static struct key_entry *keymap; /* = NULL; Current key map */
-static int have_wifi;
-static int have_bluetooth;
-static int have_leds;
+static bool have_wifi;
+static bool have_bluetooth;
+static int leds_present;       /* bitmask of leds present */
 
 static int __init dmi_matched(const struct dmi_system_id *dmi)
 {
@@ -254,11 +254,11 @@ static int __init dmi_matched(const struct dmi_system_id *dmi)
        keymap = dmi->driver_data;
        for (key = keymap; key->type != KE_END; key++) {
                if (key->type == KE_WIFI)
-                       have_wifi = 1;
+                       have_wifi = true;
                else if (key->type == KE_BLUETOOTH)
-                       have_bluetooth = 1;
+                       have_bluetooth = true;
        }
-       have_leds = key->code & (FE_MAIL_LED | FE_WIFI_LED);
+       leds_present = key->code & (FE_MAIL_LED | FE_WIFI_LED);
 
        return 1;
 }
@@ -611,10 +611,24 @@ static struct key_entry keymap_wistron_generic[] __initdata = {
        { KE_END, 0 }
 };
 
+static struct key_entry keymap_aopen_1557[] __initdata = {
+       { KE_KEY,  0x01, {KEY_HELP} },
+       { KE_KEY,  0x11, {KEY_PROG1} },
+       { KE_KEY,  0x12, {KEY_PROG2} },
+       { KE_WIFI, 0x30 },
+       { KE_KEY,  0x22, {KEY_REWIND} },
+       { KE_KEY,  0x23, {KEY_FORWARD} },
+       { KE_KEY,  0x24, {KEY_PLAYPAUSE} },
+       { KE_KEY,  0x25, {KEY_STOPCD} },
+       { KE_KEY,  0x31, {KEY_MAIL} },
+       { KE_KEY,  0x36, {KEY_WWW} },
+       { KE_END,  0 }
+};
+
 static struct key_entry keymap_prestigio[] __initdata = {
        { KE_KEY,  0x11, {KEY_PROG1} },
        { KE_KEY,  0x12, {KEY_PROG2} },
-       { KE_WIFI,  0x30 },
+       { KE_WIFI, 0x30 },
        { KE_KEY,  0x22, {KEY_REWIND} },
        { KE_KEY,  0x23, {KEY_FORWARD} },
        { KE_KEY,  0x24, {KEY_PLAYPAUSE} },
@@ -985,6 +999,8 @@ static int __init select_keymap(void)
        if (keymap_name != NULL) {
                if (strcmp (keymap_name, "1557/MS2141") == 0)
                        keymap = keymap_wistron_ms2141;
+               else if (strcmp (keymap_name, "aopen1557") == 0)
+                       keymap = keymap_aopen_1557;
                else if (strcmp (keymap_name, "prestigio") == 0)
                        keymap = keymap_prestigio;
                else if (strcmp (keymap_name, "generic") == 0)
@@ -1009,8 +1025,8 @@ static int __init select_keymap(void)
 
 static struct input_polled_dev *wistron_idev;
 static unsigned long jiffies_last_press;
-static int wifi_enabled;
-static int bluetooth_enabled;
+static bool wifi_enabled;
+static bool bluetooth_enabled;
 
 static void report_key(struct input_dev *dev, unsigned int keycode)
 {
@@ -1053,24 +1069,24 @@ static struct led_classdev wistron_wifi_led = {
 
 static void __devinit wistron_led_init(struct device *parent)
 {
-       if (have_leds & FE_WIFI_LED) {
+       if (leds_present & FE_WIFI_LED) {
                u16 wifi = bios_get_default_setting(WIFI);
                if (wifi & 1) {
                        wistron_wifi_led.brightness = (wifi & 2) ? LED_FULL : LED_OFF;
                        if (led_classdev_register(parent, &wistron_wifi_led))
-                               have_leds &= ~FE_WIFI_LED;
+                               leds_present &= ~FE_WIFI_LED;
                        else
                                bios_set_state(WIFI, wistron_wifi_led.brightness);
 
                } else
-                       have_leds &= ~FE_WIFI_LED;
+                       leds_present &= ~FE_WIFI_LED;
        }
 
-       if (have_leds & FE_MAIL_LED) {
+       if (leds_present & FE_MAIL_LED) {
                /* bios_get_default_setting(MAIL) always retuns 0, so just turn the led off */
                wistron_mail_led.brightness = LED_OFF;
                if (led_classdev_register(parent, &wistron_mail_led))
-                       have_leds &= ~FE_MAIL_LED;
+                       leds_present &= ~FE_MAIL_LED;
                else
                        bios_set_state(MAIL_LED, wistron_mail_led.brightness);
        }
@@ -1078,28 +1094,28 @@ static void __devinit wistron_led_init(struct device *parent)
 
 static void __devexit wistron_led_remove(void)
 {
-       if (have_leds & FE_MAIL_LED)
+       if (leds_present & FE_MAIL_LED)
                led_classdev_unregister(&wistron_mail_led);
 
-       if (have_leds & FE_WIFI_LED)
+       if (leds_present & FE_WIFI_LED)
                led_classdev_unregister(&wistron_wifi_led);
 }
 
 static inline void wistron_led_suspend(void)
 {
-       if (have_leds & FE_MAIL_LED)
+       if (leds_present & FE_MAIL_LED)
                led_classdev_suspend(&wistron_mail_led);
 
-       if (have_leds & FE_WIFI_LED)
+       if (leds_present & FE_WIFI_LED)
                led_classdev_suspend(&wistron_wifi_led);
 }
 
 static inline void wistron_led_resume(void)
 {
-       if (have_leds & FE_MAIL_LED)
+       if (leds_present & FE_MAIL_LED)
                led_classdev_resume(&wistron_mail_led);
 
-       if (have_leds & FE_WIFI_LED)
+       if (leds_present & FE_WIFI_LED)
                led_classdev_resume(&wistron_wifi_led);
 }
 
@@ -1312,7 +1328,7 @@ static int __devinit wistron_probe(struct platform_device *dev)
        if (have_wifi) {
                u16 wifi = bios_get_default_setting(WIFI);
                if (wifi & 1)
-                       wifi_enabled = (wifi & 2) ? 1 : 0;
+                       wifi_enabled = wifi & 2;
                else
                        have_wifi = 0;
 
@@ -1323,15 +1339,16 @@ static int __devinit wistron_probe(struct platform_device *dev)
        if (have_bluetooth) {
                u16 bt = bios_get_default_setting(BLUETOOTH);
                if (bt & 1)
-                       bluetooth_enabled = (bt & 2) ? 1 : 0;
+                       bluetooth_enabled = bt & 2;
                else
-                       have_bluetooth = 0;
+                       have_bluetooth = false;
 
                if (have_bluetooth)
                        bios_set_state(BLUETOOTH, bluetooth_enabled);
        }
 
        wistron_led_init(&dev->dev);
+
        err = setup_input_dev();
        if (err) {
                bios_detach();
@@ -1352,7 +1369,7 @@ static int __devexit wistron_remove(struct platform_device *dev)
 }
 
 #ifdef CONFIG_PM
-static int wistron_suspend(struct platform_device *dev, pm_message_t state)
+static int wistron_suspend(struct device *dev)
 {
        if (have_wifi)
                bios_set_state(WIFI, 0);
@@ -1361,10 +1378,11 @@ static int wistron_suspend(struct platform_device *dev, pm_message_t state)
                bios_set_state(BLUETOOTH, 0);
 
        wistron_led_suspend();
+
        return 0;
 }
 
-static int wistron_resume(struct platform_device *dev)
+static int wistron_resume(struct device *dev)
 {
        if (have_wifi)
                bios_set_state(WIFI, wifi_enabled);
@@ -1373,24 +1391,30 @@ static int wistron_resume(struct platform_device *dev)
                bios_set_state(BLUETOOTH, bluetooth_enabled);
 
        wistron_led_resume();
+
        poll_bios(true);
 
        return 0;
 }
-#else
-#define wistron_suspend                NULL
-#define wistron_resume         NULL
+
+static const struct dev_pm_ops wistron_pm_ops = {
+       .suspend        = wistron_suspend,
+       .resume         = wistron_resume,
+       .poweroff       = wistron_suspend,
+       .restore        = wistron_resume,
+};
 #endif
 
 static struct platform_driver wistron_driver = {
        .driver         = {
                .name   = "wistron-bios",
                .owner  = THIS_MODULE,
+#if CONFIG_PM
+               .pm     = &wistron_pm_ops,
+#endif
        },
        .probe          = wistron_probe,
        .remove         = __devexit_p(wistron_remove),
-       .suspend        = wistron_suspend,
-       .resume         = wistron_resume,
 };
 
 static int __init wb_module_init(void)
index 8a2c5b14c8d80cf8c5cee00f9435b9ef464edf82..3feeb3af8abd798f0fd544ecc12f888f1068c688 100644 (file)
@@ -107,6 +107,14 @@ config MOUSE_PS2_ELANTECH
          entries. For further information,
          see <file:Documentation/input/elantech.txt>.
 
+config MOUSE_PS2_SENTELIC
+       bool "Sentelic Finger Sensing Pad PS/2 protocol extension"
+       depends on MOUSE_PS2
+       help
+         Say Y here if you have a laptop (such as MSI WIND Netbook)
+         with Sentelic Finger Sensing Pad touchpad.
+
+         If unsure, say N.
 
 config MOUSE_PS2_TOUCHKIT
        bool "eGalax TouchKit PS/2 protocol extension"
@@ -262,14 +270,6 @@ config MOUSE_VSXXXAA
          described in the source file). This driver also works with the
          digitizer (VSXXX-AB) DEC produced.
 
-config MOUSE_HIL
-       tristate "HIL pointers (mice etc)."
-       depends on GSC || HP300
-       select HP_SDC
-       select HIL_MLC
-       help
-         Say Y here to support HIL pointers.
-
 config MOUSE_GPIO
        tristate "GPIO mouse"
        depends on GENERIC_GPIO
index 010f265ec152463b0190054c346cb80981edc43b..570c84a4a6543ce5aa8d94e3c5df0bb015243312 100644 (file)
@@ -9,7 +9,6 @@ obj-$(CONFIG_MOUSE_APPLETOUCH)          += appletouch.o
 obj-$(CONFIG_MOUSE_ATARI)              += atarimouse.o
 obj-$(CONFIG_MOUSE_BCM5974)            += bcm5974.o
 obj-$(CONFIG_MOUSE_GPIO)               += gpio_mouse.o
-obj-$(CONFIG_MOUSE_HIL)                        += hil_ptr.o
 obj-$(CONFIG_MOUSE_INPORT)             += inport.o
 obj-$(CONFIG_MOUSE_LOGIBM)             += logibm.o
 obj-$(CONFIG_MOUSE_MAPLE)              += maplemouse.o
@@ -28,5 +27,6 @@ psmouse-$(CONFIG_MOUSE_PS2_ELANTECH)  += elantech.o
 psmouse-$(CONFIG_MOUSE_PS2_OLPC)       += hgpk.o
 psmouse-$(CONFIG_MOUSE_PS2_LOGIPS2PP)  += logips2pp.o
 psmouse-$(CONFIG_MOUSE_PS2_LIFEBOOK)   += lifebook.o
+psmouse-$(CONFIG_MOUSE_PS2_SENTELIC)   += sentelic.o
 psmouse-$(CONFIG_MOUSE_PS2_TRACKPOINT) += trackpoint.o
 psmouse-$(CONFIG_MOUSE_PS2_TOUCHKIT)   += touchkit_ps2.o
index 5547e2429fbe5bc17596948c4cdb8f140f8dfa3d..f36110689aae873404e878625f3b5727f6e997ca 100644 (file)
@@ -279,7 +279,7 @@ static const struct alps_model_info *alps_get_model(struct psmouse *psmouse, int
  * subsequent commands. It looks like glidepad is behind stickpointer,
  * I'd thought it would be other way around...
  */
-static int alps_passthrough_mode(struct psmouse *psmouse, int enable)
+static int alps_passthrough_mode(struct psmouse *psmouse, bool enable)
 {
        struct ps2dev *ps2dev = &psmouse->ps2dev;
        int cmd = enable ? PSMOUSE_CMD_SETSCALE21 : PSMOUSE_CMD_SETSCALE11;
@@ -367,16 +367,16 @@ static int alps_poll(struct psmouse *psmouse)
 {
        struct alps_data *priv = psmouse->private;
        unsigned char buf[6];
-       int poll_failed;
+       bool poll_failed;
 
        if (priv->i->flags & ALPS_PASS)
-               alps_passthrough_mode(psmouse, 1);
+               alps_passthrough_mode(psmouse, true);
 
        poll_failed = ps2_command(&psmouse->ps2dev, buf,
                                  PSMOUSE_CMD_POLL | (psmouse->pktsize << 8)) < 0;
 
        if (priv->i->flags & ALPS_PASS)
-               alps_passthrough_mode(psmouse, 0);
+               alps_passthrough_mode(psmouse, false);
 
        if (poll_failed || (buf[0] & priv->i->mask0) != priv->i->byte0)
                return -1;
@@ -401,10 +401,12 @@ static int alps_hw_init(struct psmouse *psmouse, int *version)
        if (!priv->i)
                return -1;
 
-       if ((priv->i->flags & ALPS_PASS) && alps_passthrough_mode(psmouse, 1))
+       if ((priv->i->flags & ALPS_PASS) &&
+           alps_passthrough_mode(psmouse, true)) {
                return -1;
+       }
 
-       if (alps_tap_mode(psmouse, 1)) {
+       if (alps_tap_mode(psmouse, true)) {
                printk(KERN_WARNING "alps.c: Failed to enable hardware tapping\n");
                return -1;
        }
@@ -414,8 +416,10 @@ static int alps_hw_init(struct psmouse *psmouse, int *version)
                return -1;
        }
 
-       if ((priv->i->flags & ALPS_PASS) && alps_passthrough_mode(psmouse, 0))
+       if ((priv->i->flags & ALPS_PASS) &&
+           alps_passthrough_mode(psmouse, false)) {
                return -1;
+       }
 
        /* ALPS needs stream mode, otherwise it won't report any data */
        if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETSTREAM)) {
@@ -519,7 +523,7 @@ init_fail:
        return -1;
 }
 
-int alps_detect(struct psmouse *psmouse, int set_properties)
+int alps_detect(struct psmouse *psmouse, bool set_properties)
 {
        int version;
        const struct alps_model_info *model;
index 4bbddc99962b37d4a1c3869b5d77611a3123b0b7..bc87936fee1a4229202f8f462dfe774f6e2faff3 100644 (file)
@@ -26,10 +26,10 @@ struct alps_data {
 };
 
 #ifdef CONFIG_MOUSE_PS2_ALPS
-int alps_detect(struct psmouse *psmouse, int set_properties);
+int alps_detect(struct psmouse *psmouse, bool set_properties);
 int alps_init(struct psmouse *psmouse);
 #else
-inline int alps_detect(struct psmouse *psmouse, int set_properties)
+inline int alps_detect(struct psmouse *psmouse, bool set_properties)
 {
        return -ENOSYS;
 }
index 2d8fc0bf6923db46b0ee9b75aa9d83b6ba34c619..0d1d33468b437182559e5163ca668abbc8780036 100644 (file)
@@ -317,7 +317,7 @@ static int report_tp_state(struct bcm5974 *dev, int size)
        const struct tp_finger *f;
        struct input_dev *input = dev->input;
        int raw_p, raw_w, raw_x, raw_y, raw_n;
-       int ptest = 0, origin = 0, ibt = 0, nmin = 0, nmax = 0;
+       int ptest, origin, ibt = 0, nmin = 0, nmax = 0;
        int abs_p = 0, abs_w = 0, abs_x = 0, abs_y = 0;
 
        if (size < c->tp_offset || (size - c->tp_offset) % SIZEOF_FINGER != 0)
@@ -345,21 +345,22 @@ static int report_tp_state(struct bcm5974 *dev, int size)
                /* set the integrated button if applicable */
                if (c->tp_type == TYPE2)
                        ibt = raw2int(dev->tp_data[BUTTON_TYPE2]);
-       }
 
-       /* while tracking finger still valid, count all fingers */
-       if (ptest > PRESSURE_LOW && origin) {
-               abs_p = ptest;
-               abs_w = int2bound(&c->w, raw_w);
-               abs_x = int2bound(&c->x, raw_x - c->x.devmin);
-               abs_y = int2bound(&c->y, c->y.devmax - raw_y);
-               while (raw_n--) {
-                       ptest = int2bound(&c->p, raw2int(f->force_major));
-                       if (ptest > PRESSURE_LOW)
-                               nmax++;
-                       if (ptest > PRESSURE_HIGH)
-                               nmin++;
-                       f++;
+               /* while tracking finger still valid, count all fingers */
+               if (ptest > PRESSURE_LOW && origin) {
+                       abs_p = ptest;
+                       abs_w = int2bound(&c->w, raw_w);
+                       abs_x = int2bound(&c->x, raw_x - c->x.devmin);
+                       abs_y = int2bound(&c->y, c->y.devmax - raw_y);
+                       while (raw_n--) {
+                               ptest = int2bound(&c->p,
+                                                 raw2int(f->force_major));
+                               if (ptest > PRESSURE_LOW)
+                                       nmax++;
+                               if (ptest > PRESSURE_HIGH)
+                                       nmin++;
+                               f++;
+                       }
                }
        }
 
index 4bc78892ba91ca8993575b8fbea2efabab6295a2..fda35e615abf9c7b594d905dfed0027575e78a49 100644 (file)
@@ -553,7 +553,7 @@ static struct attribute_group elantech_attr_group = {
 /*
  * Use magic knock to detect Elantech touchpad
  */
-int elantech_detect(struct psmouse *psmouse, int set_properties)
+int elantech_detect(struct psmouse *psmouse, bool set_properties)
 {
        struct ps2dev *ps2dev = &psmouse->ps2dev;
        unsigned char param[3];
index ed848cc808140e70d03eb3bacadd99925d6449ce..feac5f7af966f5393b8dfaebeba2a7ceef31a70b 100644 (file)
@@ -109,10 +109,10 @@ struct elantech_data {
 };
 
 #ifdef CONFIG_MOUSE_PS2_ELANTECH
-int elantech_detect(struct psmouse *psmouse, int set_properties);
+int elantech_detect(struct psmouse *psmouse, bool set_properties);
 int elantech_init(struct psmouse *psmouse);
 #else
-static inline int elantech_detect(struct psmouse *psmouse, int set_properties)
+static inline int elantech_detect(struct psmouse *psmouse, bool set_properties)
 {
        return -ENOSYS;
 }
index a1ad2f1a7bb377c776368d55c2a05b5fcd7fd69b..de1e553028b7573ee7ab0577e6c4415683293435 100644 (file)
@@ -367,7 +367,36 @@ static ssize_t hgpk_set_powered(struct psmouse *psmouse, void *data,
 }
 
 __PSMOUSE_DEFINE_ATTR(powered, S_IWUSR | S_IRUGO, NULL,
-                     hgpk_show_powered, hgpk_set_powered, 0);
+                     hgpk_show_powered, hgpk_set_powered, false);
+
+static ssize_t hgpk_trigger_recal_show(struct psmouse *psmouse,
+               void *data, char *buf)
+{
+       return -EINVAL;
+}
+
+static ssize_t hgpk_trigger_recal(struct psmouse *psmouse, void *data,
+                               const char *buf, size_t count)
+{
+       struct hgpk_data *priv = psmouse->private;
+       unsigned long value;
+       int err;
+
+       err = strict_strtoul(buf, 10, &value);
+       if (err || value != 1)
+               return -EINVAL;
+
+       /*
+        * We queue work instead of doing recalibration right here
+        * to avoid adding locking to to hgpk_force_recalibrate()
+        * since workqueue provides serialization.
+        */
+       psmouse_queue_work(psmouse, &priv->recalib_wq, 0);
+       return count;
+}
+
+__PSMOUSE_DEFINE_ATTR(recalibrate, S_IWUSR | S_IRUGO, NULL,
+                     hgpk_trigger_recal_show, hgpk_trigger_recal, false);
 
 static void hgpk_disconnect(struct psmouse *psmouse)
 {
@@ -375,6 +404,11 @@ static void hgpk_disconnect(struct psmouse *psmouse)
 
        device_remove_file(&psmouse->ps2dev.serio->dev,
                           &psmouse_attr_powered.dattr);
+
+       if (psmouse->model >= HGPK_MODEL_C)
+               device_remove_file(&psmouse->ps2dev.serio->dev,
+                                  &psmouse_attr_recalibrate.dattr);
+
        psmouse_reset(psmouse);
        kfree(priv);
 }
@@ -423,10 +457,25 @@ static int hgpk_register(struct psmouse *psmouse)
 
        err = device_create_file(&psmouse->ps2dev.serio->dev,
                                 &psmouse_attr_powered.dattr);
-       if (err)
-               hgpk_err(psmouse, "Failed to create sysfs attribute\n");
+       if (err) {
+               hgpk_err(psmouse, "Failed creating 'powered' sysfs node\n");
+               return err;
+       }
 
-       return err;
+       /* C-series touchpads added the recalibrate command */
+       if (psmouse->model >= HGPK_MODEL_C) {
+               err = device_create_file(&psmouse->ps2dev.serio->dev,
+                                        &psmouse_attr_recalibrate.dattr);
+               if (err) {
+                       hgpk_err(psmouse,
+                               "Failed creating 'recalibrate' sysfs node\n");
+                       device_remove_file(&psmouse->ps2dev.serio->dev,
+                                       &psmouse_attr_powered.dattr);
+                       return err;
+               }
+       }
+
+       return 0;
 }
 
 int hgpk_init(struct psmouse *psmouse)
@@ -440,7 +489,7 @@ int hgpk_init(struct psmouse *psmouse)
 
        psmouse->private = priv;
        priv->psmouse = psmouse;
-       priv->powered = 1;
+       priv->powered = true;
        INIT_DELAYED_WORK(&priv->recalib_wq, hgpk_recalib_work);
 
        err = psmouse_reset(psmouse);
@@ -483,7 +532,7 @@ static enum hgpk_model_t hgpk_get_model(struct psmouse *psmouse)
        return param[2];
 }
 
-int hgpk_detect(struct psmouse *psmouse, int set_properties)
+int hgpk_detect(struct psmouse *psmouse, bool set_properties)
 {
        int version;
 
index a4b2a96f5f54593cbb17e3af56185577cc69be0d..d61cfd3ee9cb2f1e176ad0bc10db6330b1a16d3b 100644 (file)
@@ -15,7 +15,7 @@ enum hgpk_model_t {
 
 struct hgpk_data {
        struct psmouse *psmouse;
-       int powered;
+       bool powered;
        int count, x_tally, y_tally;    /* hardware workaround stuff */
        unsigned long recalib_window;
        struct delayed_work recalib_wq;
@@ -33,10 +33,10 @@ struct hgpk_data {
        dev_notice(&(psmouse)->ps2dev.serio->dev, format, ## arg)
 
 #ifdef CONFIG_MOUSE_PS2_OLPC
-int hgpk_detect(struct psmouse *psmouse, int set_properties);
+int hgpk_detect(struct psmouse *psmouse, bool set_properties);
 int hgpk_init(struct psmouse *psmouse);
 #else
-static inline int hgpk_detect(struct psmouse *psmouse, int set_properties)
+static inline int hgpk_detect(struct psmouse *psmouse, bool set_properties)
 {
        return -ENODEV;
 }
diff --git a/drivers/input/mouse/hil_ptr.c b/drivers/input/mouse/hil_ptr.c
deleted file mode 100644 (file)
index 3263ce0..0000000
+++ /dev/null
@@ -1,447 +0,0 @@
-/*
- * Generic linux-input device driver for axis-bearing devices
- *
- * Copyright (c) 2001 Brian S. Julin
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions, and the following disclaimer,
- *    without modification.
- * 2. The name of the author may not be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- *
- * Alternatively, this software may be distributed under the terms of the
- * GNU General Public License ("GPL").
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- *
- * References:
- * HP-HIL Technical Reference Manual.  Hewlett Packard Product No. 45918A
- *
- */
-
-#include <linux/hil.h>
-#include <linux/input.h>
-#include <linux/serio.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/pci_ids.h>
-
-#define PREFIX "HIL PTR: "
-#define HIL_GENERIC_NAME "HIL pointer device"
-
-MODULE_AUTHOR("Brian S. Julin <bri@calyx.com>");
-MODULE_DESCRIPTION(HIL_GENERIC_NAME " driver");
-MODULE_LICENSE("Dual BSD/GPL");
-MODULE_ALIAS("serio:ty03pr25id0Fex*");
-
-#define TABLET_SIMULATES_MOUSE /* allow tablet to be used as mouse */
-#undef  TABLET_AUTOADJUST      /* auto-adjust valid tablet ranges */
-
-
-#define HIL_PTR_MAX_LENGTH 16
-
-struct hil_ptr {
-       struct input_dev *dev;
-       struct serio *serio;
-
-       /* Input buffer and index for packets from HIL bus. */
-       hil_packet data[HIL_PTR_MAX_LENGTH];
-       int idx4; /* four counts per packet */
-
-       /* Raw device info records from HIL bus, see hil.h for fields. */
-       char    idd[HIL_PTR_MAX_LENGTH];        /* DID byte and IDD record */
-       char    rsc[HIL_PTR_MAX_LENGTH];        /* RSC record */
-       char    exd[HIL_PTR_MAX_LENGTH];        /* EXD record */
-       char    rnm[HIL_PTR_MAX_LENGTH + 1];    /* RNM record + NULL term. */
-
-       /* Extra device details not contained in struct input_dev. */
-       unsigned int nbtn, naxes;
-       unsigned int btnmap[7];
-
-       /* Something to sleep around with. */
-       struct semaphore sem;
-};
-
-/* Process a complete packet after transfer from the HIL */
-static void hil_ptr_process_record(struct hil_ptr *ptr)
-{
-       struct input_dev *dev = ptr->dev;
-       hil_packet *data = ptr->data;
-       hil_packet p;
-       int idx, i, cnt, laxis;
-       int ax16, absdev;
-
-       idx = ptr->idx4/4;
-       p = data[idx - 1];
-
-       if ((p & ~HIL_CMDCT_POL) ==
-           (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_POL))
-               goto report;
-       if ((p & ~HIL_CMDCT_RPL) ==
-           (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_RPL))
-               goto report;
-
-       /* Not a poll response.  See if we are loading config records. */
-       switch (p & HIL_PKT_DATA_MASK) {
-       case HIL_CMD_IDD:
-               for (i = 0; i < idx; i++)
-                       ptr->idd[i] = ptr->data[i] & HIL_PKT_DATA_MASK;
-               for (; i < HIL_PTR_MAX_LENGTH; i++)
-                       ptr->idd[i] = 0;
-               break;
-
-       case HIL_CMD_RSC:
-               for (i = 0; i < idx; i++)
-                       ptr->rsc[i] = ptr->data[i] & HIL_PKT_DATA_MASK;
-               for (; i < HIL_PTR_MAX_LENGTH; i++)
-                       ptr->rsc[i] = 0;
-               break;
-
-       case HIL_CMD_EXD:
-               for (i = 0; i < idx; i++)
-                       ptr->exd[i] = ptr->data[i] & HIL_PKT_DATA_MASK;
-               for (; i < HIL_PTR_MAX_LENGTH; i++)
-                       ptr->exd[i] = 0;
-               break;
-
-       case HIL_CMD_RNM:
-               for (i = 0; i < idx; i++)
-                       ptr->rnm[i] = ptr->data[i] & HIL_PKT_DATA_MASK;
-               for (; i < HIL_PTR_MAX_LENGTH + 1; i++)
-                       ptr->rnm[i] = 0;
-               break;
-
-       default:
-               /* These occur when device isn't present */
-               if (p == (HIL_ERR_INT | HIL_PKT_CMD))
-                       break;
-               /* Anything else we'd like to know about. */
-               printk(KERN_WARNING PREFIX "Device sent unknown record %x\n", p);
-               break;
-       }
-       goto out;
-
- report:
-       if ((p & HIL_CMDCT_POL) != idx - 1) {
-               printk(KERN_WARNING PREFIX
-                       "Malformed poll packet %x (idx = %i)\n", p, idx);
-               goto out;
-       }
-
-       i = (ptr->data[0] & HIL_POL_AXIS_ALT) ? 3 : 0;
-       laxis = ptr->data[0] & HIL_POL_NUM_AXES_MASK;
-       laxis += i;
-
-       ax16 = ptr->idd[1] & HIL_IDD_HEADER_16BIT; /* 8 or 16bit resolution */
-       absdev = ptr->idd[1] & HIL_IDD_HEADER_ABS;
-
-       for (cnt = 1; i < laxis; i++) {
-               unsigned int lo,hi,val;
-               lo = ptr->data[cnt++] & HIL_PKT_DATA_MASK;
-               hi = ax16 ? (ptr->data[cnt++] & HIL_PKT_DATA_MASK) : 0;
-               if (absdev) {
-                       val = lo + (hi<<8);
-#ifdef TABLET_AUTOADJUST
-                       if (val < dev->absmin[ABS_X + i])
-                               dev->absmin[ABS_X + i] = val;
-                       if (val > dev->absmax[ABS_X + i])
-                               dev->absmax[ABS_X + i] = val;
-#endif
-                       if (i%3) val = dev->absmax[ABS_X + i] - val;
-                       input_report_abs(dev, ABS_X + i, val);
-               } else {
-                       val = (int) (((int8_t)lo) | ((int8_t)hi<<8));
-                       if (i%3)
-                               val *= -1;
-                       input_report_rel(dev, REL_X + i, val);
-               }
-       }
-
-       while (cnt < idx - 1) {
-               unsigned int btn;
-               int up;
-               btn = ptr->data[cnt++];
-               up = btn & 1;
-               btn &= 0xfe;
-               if (btn == 0x8e)
-                       continue; /* TODO: proximity == touch? */
-               else
-                       if ((btn > 0x8c) || (btn < 0x80))
-                               continue;
-               btn = (btn - 0x80) >> 1;
-               btn = ptr->btnmap[btn];
-               input_report_key(dev, btn, !up);
-       }
-       input_sync(dev);
- out:
-       ptr->idx4 = 0;
-       up(&ptr->sem);
-}
-
-static void hil_ptr_process_err(struct hil_ptr *ptr)
-{
-       printk(KERN_WARNING PREFIX "errored HIL packet\n");
-       ptr->idx4 = 0;
-       up(&ptr->sem);
-}
-
-static irqreturn_t hil_ptr_interrupt(struct serio *serio,
-        unsigned char data, unsigned int flags)
-{
-       struct hil_ptr *ptr;
-       hil_packet packet;
-       int idx;
-
-       ptr = serio_get_drvdata(serio);
-       BUG_ON(ptr == NULL);
-
-       if (ptr->idx4 >= (HIL_PTR_MAX_LENGTH * sizeof(hil_packet))) {
-               hil_ptr_process_err(ptr);
-               return IRQ_HANDLED;
-       }
-       idx = ptr->idx4/4;
-       if (!(ptr->idx4 % 4))
-               ptr->data[idx] = 0;
-       packet = ptr->data[idx];
-       packet |= ((hil_packet)data) << ((3 - (ptr->idx4 % 4)) * 8);
-       ptr->data[idx] = packet;
-
-       /* Records of N 4-byte hil_packets must terminate with a command. */
-       if ((++(ptr->idx4)) % 4)
-               return IRQ_HANDLED;
-       if ((packet & 0xffff0000) != HIL_ERR_INT) {
-               hil_ptr_process_err(ptr);
-               return IRQ_HANDLED;
-       }
-       if (packet & HIL_PKT_CMD)
-               hil_ptr_process_record(ptr);
-
-       return IRQ_HANDLED;
-}
-
-static void hil_ptr_disconnect(struct serio *serio)
-{
-       struct hil_ptr *ptr;
-
-       ptr = serio_get_drvdata(serio);
-       BUG_ON(ptr == NULL);
-
-       serio_close(serio);
-       input_unregister_device(ptr->dev);
-       kfree(ptr);
-}
-
-static int hil_ptr_connect(struct serio *serio, struct serio_driver *driver)
-{
-       struct hil_ptr  *ptr;
-       const char      *txt;
-       unsigned int    i, naxsets, btntype;
-       uint8_t         did, *idd;
-       int             error;
-
-       ptr = kzalloc(sizeof(struct hil_ptr), GFP_KERNEL);
-       if (!ptr)
-               return -ENOMEM;
-
-       ptr->dev = input_allocate_device();
-       if (!ptr->dev) {
-               error = -ENOMEM;
-               goto bail0;
-       }
-
-       error = serio_open(serio, driver);
-       if (error)
-               goto bail1;
-
-       serio_set_drvdata(serio, ptr);
-       ptr->serio = serio;
-
-       init_MUTEX_LOCKED(&ptr->sem);
-
-       /* Get device info.  MLC driver supplies devid/status/etc. */
-       serio->write(serio, 0);
-       serio->write(serio, 0);
-       serio->write(serio, HIL_PKT_CMD >> 8);
-       serio->write(serio, HIL_CMD_IDD);
-       down(&ptr->sem);
-
-       serio->write(serio, 0);
-       serio->write(serio, 0);
-       serio->write(serio, HIL_PKT_CMD >> 8);
-       serio->write(serio, HIL_CMD_RSC);
-       down(&ptr->sem);
-
-       serio->write(serio, 0);
-       serio->write(serio, 0);
-       serio->write(serio, HIL_PKT_CMD >> 8);
-       serio->write(serio, HIL_CMD_RNM);
-       down(&ptr->sem);
-
-       serio->write(serio, 0);
-       serio->write(serio, 0);
-       serio->write(serio, HIL_PKT_CMD >> 8);
-       serio->write(serio, HIL_CMD_EXD);
-       down(&ptr->sem);
-
-       up(&ptr->sem);
-
-       did = ptr->idd[0];
-       idd = ptr->idd + 1;
-       txt = "unknown";
-
-       if ((did & HIL_IDD_DID_TYPE_MASK) == HIL_IDD_DID_TYPE_REL) {
-               ptr->dev->evbit[0] = BIT_MASK(EV_REL);
-               txt = "relative";
-       }
-
-       if ((did & HIL_IDD_DID_TYPE_MASK) == HIL_IDD_DID_TYPE_ABS) {
-               ptr->dev->evbit[0] = BIT_MASK(EV_ABS);
-               txt = "absolute";
-       }
-
-       if (!ptr->dev->evbit[0]) {
-               error = -ENODEV;
-               goto bail2;
-       }
-
-       ptr->nbtn = HIL_IDD_NUM_BUTTONS(idd);
-       if (ptr->nbtn)
-               ptr->dev->evbit[0] |= BIT_MASK(EV_KEY);
-
-       naxsets = HIL_IDD_NUM_AXSETS(*idd);
-       ptr->naxes = HIL_IDD_NUM_AXES_PER_SET(*idd);
-
-       printk(KERN_INFO PREFIX "HIL pointer device found (did: 0x%02x, axis: %s)\n",
-                       did, txt);
-       printk(KERN_INFO PREFIX "HIL pointer has %i buttons and %i sets of %i axes\n",
-                       ptr->nbtn, naxsets, ptr->naxes);
-
-       btntype = BTN_MISC;
-       if ((did & HIL_IDD_DID_ABS_TABLET_MASK) == HIL_IDD_DID_ABS_TABLET)
-#ifdef TABLET_SIMULATES_MOUSE
-               btntype = BTN_TOUCH;
-#else
-               btntype = BTN_DIGI;
-#endif
-       if ((did & HIL_IDD_DID_ABS_TSCREEN_MASK) == HIL_IDD_DID_ABS_TSCREEN)
-               btntype = BTN_TOUCH;
-
-       if ((did & HIL_IDD_DID_REL_MOUSE_MASK) == HIL_IDD_DID_REL_MOUSE)
-               btntype = BTN_MOUSE;
-
-       for (i = 0; i < ptr->nbtn; i++) {
-               set_bit(btntype | i, ptr->dev->keybit);
-               ptr->btnmap[i] = btntype | i;
-       }
-
-       if (btntype == BTN_MOUSE) {
-               /* Swap buttons 2 and 3 */
-               ptr->btnmap[1] = BTN_MIDDLE;
-               ptr->btnmap[2] = BTN_RIGHT;
-       }
-
-       if ((did & HIL_IDD_DID_TYPE_MASK) == HIL_IDD_DID_TYPE_REL) {
-               for (i = 0; i < ptr->naxes; i++)
-                       set_bit(REL_X + i, ptr->dev->relbit);
-               for (i = 3; (i < ptr->naxes + 3) && (naxsets > 1); i++)
-                       set_bit(REL_X + i, ptr->dev->relbit);
-       } else {
-               for (i = 0; i < ptr->naxes; i++) {
-                       set_bit(ABS_X + i, ptr->dev->absbit);
-                       ptr->dev->absmin[ABS_X + i] = 0;
-                       ptr->dev->absmax[ABS_X + i] =
-                               HIL_IDD_AXIS_MAX((ptr->idd + 1), i);
-               }
-               for (i = 3; (i < ptr->naxes + 3) && (naxsets > 1); i++) {
-                       set_bit(ABS_X + i, ptr->dev->absbit);
-                       ptr->dev->absmin[ABS_X + i] = 0;
-                       ptr->dev->absmax[ABS_X + i] =
-                               HIL_IDD_AXIS_MAX((ptr->idd + 1), (i - 3));
-               }
-#ifdef TABLET_AUTOADJUST
-               for (i = 0; i < ABS_MAX; i++) {
-                       int diff = ptr->dev->absmax[ABS_X + i] / 10;
-                       ptr->dev->absmin[ABS_X + i] += diff;
-                       ptr->dev->absmax[ABS_X + i] -= diff;
-               }
-#endif
-       }
-
-       ptr->dev->name = strlen(ptr->rnm) ? ptr->rnm : HIL_GENERIC_NAME;
-
-       ptr->dev->id.bustype    = BUS_HIL;
-       ptr->dev->id.vendor     = PCI_VENDOR_ID_HP;
-       ptr->dev->id.product    = 0x0001; /* TODO: get from ptr->rsc */
-       ptr->dev->id.version    = 0x0100; /* TODO: get from ptr->rsc */
-       ptr->dev->dev.parent    = &serio->dev;
-
-       error = input_register_device(ptr->dev);
-       if (error) {
-               printk(KERN_INFO PREFIX "Unable to register input device\n");
-               goto bail2;
-       }
-
-       printk(KERN_INFO "input: %s (%s), ID: %d\n",
-               ptr->dev->name,
-               (btntype == BTN_MOUSE) ? "HIL mouse":"HIL tablet or touchpad",
-               did);
-
-       return 0;
-
- bail2:
-       serio_close(serio);
- bail1:
-       input_free_device(ptr->dev);
- bail0:
-       kfree(ptr);
-       serio_set_drvdata(serio, NULL);
-       return error;
-}
-
-static struct serio_device_id hil_ptr_ids[] = {
-       {
-               .type = SERIO_HIL_MLC,
-               .proto = SERIO_HIL,
-               .id = SERIO_ANY,
-               .extra = SERIO_ANY,
-       },
-       { 0 }
-};
-
-static struct serio_driver hil_ptr_serio_driver = {
-       .driver         = {
-               .name   = "hil_ptr",
-       },
-       .description    = "HP HIL mouse/tablet driver",
-       .id_table       = hil_ptr_ids,
-       .connect        = hil_ptr_connect,
-       .disconnect     = hil_ptr_disconnect,
-       .interrupt      = hil_ptr_interrupt
-};
-
-static int __init hil_ptr_init(void)
-{
-       return serio_register_driver(&hil_ptr_serio_driver);
-}
-
-static void __exit hil_ptr_exit(void)
-{
-       serio_unregister_driver(&hil_ptr_serio_driver);
-}
-
-module_init(hil_ptr_init);
-module_exit(hil_ptr_exit);
index dcd4236af1e33b038bcba36fc711c35c8695fd1d..5e6308694408d695515264885ea906053191136c 100644 (file)
@@ -33,11 +33,11 @@ static int lifebook_set_serio_phys(const struct dmi_system_id *d)
        return 0;
 }
 
-static unsigned char lifebook_use_6byte_proto;
+static bool lifebook_use_6byte_proto;
 
 static int lifebook_set_6byte_proto(const struct dmi_system_id *d)
 {
-       lifebook_use_6byte_proto = 1;
+       lifebook_use_6byte_proto = true;
        return 0;
 }
 
@@ -125,7 +125,7 @@ static psmouse_ret_t lifebook_process_byte(struct psmouse *psmouse)
        struct input_dev *dev1 = psmouse->dev;
        struct input_dev *dev2 = priv ? priv->dev2 : NULL;
        unsigned char *packet = psmouse->packet;
-       int relative_packet = packet[0] & 0x08;
+       bool relative_packet = packet[0] & 0x08;
 
        if (relative_packet || !lifebook_use_6byte_proto) {
                if (psmouse->pktcnt != 3)
@@ -242,7 +242,7 @@ static void lifebook_disconnect(struct psmouse *psmouse)
        psmouse->private = NULL;
 }
 
-int lifebook_detect(struct psmouse *psmouse, int set_properties)
+int lifebook_detect(struct psmouse *psmouse, bool set_properties)
 {
         if (!dmi_check_system(lifebook_dmi_table))
                 return -1;
index c1647cf036c25e8ebe7e0962f0139342f5af8dff..407cb226bc0a85d98df848d6a3b29a533777ce61 100644 (file)
 #define _LIFEBOOK_H
 
 #ifdef CONFIG_MOUSE_PS2_LIFEBOOK
-int lifebook_detect(struct psmouse *psmouse, int set_properties);
+int lifebook_detect(struct psmouse *psmouse, bool set_properties);
 int lifebook_init(struct psmouse *psmouse);
 #else
-inline int lifebook_detect(struct psmouse *psmouse, int set_properties)
+inline int lifebook_detect(struct psmouse *psmouse, bool set_properties)
 {
        return -ENOSYS;
 }
index 390f1dbb98a482d855154119fa45ff52f3ea6bca..de745d7511624ab8a488eb17066db9252e6d1190 100644 (file)
@@ -130,14 +130,11 @@ static int ps2pp_cmd(struct psmouse *psmouse, unsigned char *param, unsigned cha
  * 0 - disabled
  */
 
-static void ps2pp_set_smartscroll(struct psmouse *psmouse, unsigned int smartscroll)
+static void ps2pp_set_smartscroll(struct psmouse *psmouse, bool smartscroll)
 {
        struct ps2dev *ps2dev = &psmouse->ps2dev;
        unsigned char param[4];
 
-       if (smartscroll > 1)
-               smartscroll = 1;
-
        ps2pp_cmd(psmouse, param, 0x32);
 
        param[0] = 0;
@@ -149,12 +146,14 @@ static void ps2pp_set_smartscroll(struct psmouse *psmouse, unsigned int smartscr
        ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
 }
 
-static ssize_t ps2pp_attr_show_smartscroll(struct psmouse *psmouse, void *data, char *buf)
+static ssize_t ps2pp_attr_show_smartscroll(struct psmouse *psmouse,
+                                          void *data, char *buf)
 {
-       return sprintf(buf, "%d\n", psmouse->smartscroll ? 1 : 0);
+       return sprintf(buf, "%d\n", psmouse->smartscroll);
 }
 
-static ssize_t ps2pp_attr_set_smartscroll(struct psmouse *psmouse, void *data, const char *buf, size_t count)
+static ssize_t ps2pp_attr_set_smartscroll(struct psmouse *psmouse, void *data,
+                                         const char *buf, size_t count)
 {
        unsigned long value;
 
@@ -261,29 +260,29 @@ static const struct ps2pp_info *get_model_info(unsigned char model)
 
 static void ps2pp_set_model_properties(struct psmouse *psmouse,
                                       const struct ps2pp_info *model_info,
-                                      int using_ps2pp)
+                                      bool using_ps2pp)
 {
        struct input_dev *input_dev = psmouse->dev;
 
        if (model_info->features & PS2PP_SIDE_BTN)
-               set_bit(BTN_SIDE, input_dev->keybit);
+               __set_bit(BTN_SIDE, input_dev->keybit);
 
        if (model_info->features & PS2PP_EXTRA_BTN)
-               set_bit(BTN_EXTRA, input_dev->keybit);
+               __set_bit(BTN_EXTRA, input_dev->keybit);
 
        if (model_info->features & PS2PP_TASK_BTN)
-               set_bit(BTN_TASK, input_dev->keybit);
+               __set_bit(BTN_TASK, input_dev->keybit);
 
        if (model_info->features & PS2PP_NAV_BTN) {
-               set_bit(BTN_FORWARD, input_dev->keybit);
-               set_bit(BTN_BACK, input_dev->keybit);
+               __set_bit(BTN_FORWARD, input_dev->keybit);
+               __set_bit(BTN_BACK, input_dev->keybit);
        }
 
        if (model_info->features & PS2PP_WHEEL)
-               set_bit(REL_WHEEL, input_dev->relbit);
+               __set_bit(REL_WHEEL, input_dev->relbit);
 
        if (model_info->features & PS2PP_HWHEEL)
-               set_bit(REL_HWHEEL, input_dev->relbit);
+               __set_bit(REL_HWHEEL, input_dev->relbit);
 
        switch (model_info->kind) {
                case PS2PP_KIND_WHEEL:
@@ -321,13 +320,13 @@ static void ps2pp_set_model_properties(struct psmouse *psmouse,
  * that support it.
  */
 
-int ps2pp_init(struct psmouse *psmouse, int set_properties)
+int ps2pp_init(struct psmouse *psmouse, bool set_properties)
 {
        struct ps2dev *ps2dev = &psmouse->ps2dev;
        unsigned char param[4];
        unsigned char model, buttons;
        const struct ps2pp_info *model_info;
-       int use_ps2pp = 0;
+       bool use_ps2pp = false;
        int error;
 
        param[0] = 0;
@@ -364,7 +363,7 @@ int ps2pp_init(struct psmouse *psmouse, int set_properties)
                        param[0] = 0;
                        if (!ps2_command(ps2dev, param, 0x13d1) &&
                            param[0] == 0x06 && param[1] == 0x00 && param[2] == 0x14) {
-                               use_ps2pp = 1;
+                               use_ps2pp = true;
                        }
 
                } else {
@@ -376,8 +375,8 @@ int ps2pp_init(struct psmouse *psmouse, int set_properties)
                        if ((param[0] & 0x78) == 0x48 &&
                            (param[1] & 0xf3) == 0xc2 &&
                            (param[2] & 0x03) == ((param[1] >> 2) & 3)) {
-                               ps2pp_set_smartscroll(psmouse, psmouse->smartscroll);
-                               use_ps2pp = 1;
+                               ps2pp_set_smartscroll(psmouse, false);
+                               use_ps2pp = true;
                        }
                }
        }
@@ -406,7 +405,7 @@ int ps2pp_init(struct psmouse *psmouse, int set_properties)
                }
 
                if (buttons < 3)
-                       clear_bit(BTN_MIDDLE, psmouse->dev->keybit);
+                       __clear_bit(BTN_MIDDLE, psmouse->dev->keybit);
 
                if (model_info)
                        ps2pp_set_model_properties(psmouse, model_info, use_ps2pp);
index 6e5712525fd618b9475a92488ec6177c847f076e..0c186f0282d973461f0c90dfbb12f40eabc0b85f 100644 (file)
@@ -12,9 +12,9 @@
 #define _LOGIPS2PP_H
 
 #ifdef CONFIG_MOUSE_PS2_LOGIPS2PP
-int ps2pp_init(struct psmouse *psmouse, int set_properties);
+int ps2pp_init(struct psmouse *psmouse, bool set_properties);
 #else
-inline int ps2pp_init(struct psmouse *psmouse, int set_properties)
+inline int ps2pp_init(struct psmouse *psmouse, bool set_properties)
 {
        return -ENOSYS;
 }
index b407b355dcebb6ff8e67617047d8878d742d1ef5..690aed90543694e0c4d94cf6e8234bbef228843e 100644 (file)
@@ -30,6 +30,7 @@
 #include "trackpoint.h"
 #include "touchkit_ps2.h"
 #include "elantech.h"
+#include "sentelic.h"
 
 #define DRIVER_DESC    "PS/2 mouse driver"
 
@@ -108,10 +109,10 @@ static struct workqueue_struct *kpsmoused_wq;
 
 struct psmouse_protocol {
        enum psmouse_type type;
+       bool maxproto;
        const char *name;
        const char *alias;
-       int maxproto;
-       int (*detect)(struct psmouse *, int);
+       int (*detect)(struct psmouse *, bool);
        int (*init)(struct psmouse *);
 };
 
@@ -216,7 +217,7 @@ void psmouse_queue_work(struct psmouse *psmouse, struct delayed_work *work,
 static inline void __psmouse_set_state(struct psmouse *psmouse, enum psmouse_state new_state)
 {
        psmouse->state = new_state;
-       psmouse->pktcnt = psmouse->out_of_sync = 0;
+       psmouse->pktcnt = psmouse->out_of_sync_cnt = 0;
        psmouse->ps2dev.flags = 0;
        psmouse->last = jiffies;
 }
@@ -249,7 +250,7 @@ static int psmouse_handle_byte(struct psmouse *psmouse)
                        if (psmouse->state == PSMOUSE_ACTIVATED) {
                                printk(KERN_WARNING "psmouse.c: %s at %s lost sync at byte %d\n",
                                        psmouse->name, psmouse->phys, psmouse->pktcnt);
-                               if (++psmouse->out_of_sync == psmouse->resetafter) {
+                               if (++psmouse->out_of_sync_cnt == psmouse->resetafter) {
                                        __psmouse_set_state(psmouse, PSMOUSE_IGNORE);
                                        printk(KERN_NOTICE "psmouse.c: issuing reconnect request\n");
                                        serio_reconnect(psmouse->ps2dev.serio);
@@ -261,8 +262,8 @@ static int psmouse_handle_byte(struct psmouse *psmouse)
 
                case PSMOUSE_FULL_PACKET:
                        psmouse->pktcnt = 0;
-                       if (psmouse->out_of_sync) {
-                               psmouse->out_of_sync = 0;
+                       if (psmouse->out_of_sync_cnt) {
+                               psmouse->out_of_sync_cnt = 0;
                                printk(KERN_NOTICE "psmouse.c: %s at %s - driver resynched.\n",
                                        psmouse->name, psmouse->phys);
                        }
@@ -408,7 +409,7 @@ int psmouse_reset(struct psmouse *psmouse)
 /*
  * Genius NetMouse magic init.
  */
-static int genius_detect(struct psmouse *psmouse, int set_properties)
+static int genius_detect(struct psmouse *psmouse, bool set_properties)
 {
        struct ps2dev *ps2dev = &psmouse->ps2dev;
        unsigned char param[4];
@@ -424,9 +425,9 @@ static int genius_detect(struct psmouse *psmouse, int set_properties)
                return -1;
 
        if (set_properties) {
-               set_bit(BTN_EXTRA, psmouse->dev->keybit);
-               set_bit(BTN_SIDE, psmouse->dev->keybit);
-               set_bit(REL_WHEEL, psmouse->dev->relbit);
+               __set_bit(BTN_EXTRA, psmouse->dev->keybit);
+               __set_bit(BTN_SIDE, psmouse->dev->keybit);
+               __set_bit(REL_WHEEL, psmouse->dev->relbit);
 
                psmouse->vendor = "Genius";
                psmouse->name = "Mouse";
@@ -439,7 +440,7 @@ static int genius_detect(struct psmouse *psmouse, int set_properties)
 /*
  * IntelliMouse magic init.
  */
-static int intellimouse_detect(struct psmouse *psmouse, int set_properties)
+static int intellimouse_detect(struct psmouse *psmouse, bool set_properties)
 {
        struct ps2dev *ps2dev = &psmouse->ps2dev;
        unsigned char param[2];
@@ -456,8 +457,8 @@ static int intellimouse_detect(struct psmouse *psmouse, int set_properties)
                return -1;
 
        if (set_properties) {
-               set_bit(BTN_MIDDLE, psmouse->dev->keybit);
-               set_bit(REL_WHEEL, psmouse->dev->relbit);
+               __set_bit(BTN_MIDDLE, psmouse->dev->keybit);
+               __set_bit(REL_WHEEL, psmouse->dev->relbit);
 
                if (!psmouse->vendor) psmouse->vendor = "Generic";
                if (!psmouse->name) psmouse->name = "Wheel Mouse";
@@ -470,7 +471,7 @@ static int intellimouse_detect(struct psmouse *psmouse, int set_properties)
 /*
  * Try IntelliMouse/Explorer magic init.
  */
-static int im_explorer_detect(struct psmouse *psmouse, int set_properties)
+static int im_explorer_detect(struct psmouse *psmouse, bool set_properties)
 {
        struct ps2dev *ps2dev = &psmouse->ps2dev;
        unsigned char param[2];
@@ -497,11 +498,11 @@ static int im_explorer_detect(struct psmouse *psmouse, int set_properties)
        ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
 
        if (set_properties) {
-               set_bit(BTN_MIDDLE, psmouse->dev->keybit);
-               set_bit(REL_WHEEL, psmouse->dev->relbit);
-               set_bit(REL_HWHEEL, psmouse->dev->relbit);
-               set_bit(BTN_SIDE, psmouse->dev->keybit);
-               set_bit(BTN_EXTRA, psmouse->dev->keybit);
+               __set_bit(BTN_MIDDLE, psmouse->dev->keybit);
+               __set_bit(REL_WHEEL, psmouse->dev->relbit);
+               __set_bit(REL_HWHEEL, psmouse->dev->relbit);
+               __set_bit(BTN_SIDE, psmouse->dev->keybit);
+               __set_bit(BTN_EXTRA, psmouse->dev->keybit);
 
                if (!psmouse->vendor) psmouse->vendor = "Generic";
                if (!psmouse->name) psmouse->name = "Explorer Mouse";
@@ -514,7 +515,7 @@ static int im_explorer_detect(struct psmouse *psmouse, int set_properties)
 /*
  * Kensington ThinkingMouse / ExpertMouse magic init.
  */
-static int thinking_detect(struct psmouse *psmouse, int set_properties)
+static int thinking_detect(struct psmouse *psmouse, bool set_properties)
 {
        struct ps2dev *ps2dev = &psmouse->ps2dev;
        unsigned char param[2];
@@ -535,7 +536,7 @@ static int thinking_detect(struct psmouse *psmouse, int set_properties)
                return -1;
 
        if (set_properties) {
-               set_bit(BTN_EXTRA, psmouse->dev->keybit);
+               __set_bit(BTN_EXTRA, psmouse->dev->keybit);
 
                psmouse->vendor = "Kensington";
                psmouse->name = "ThinkingMouse";
@@ -547,7 +548,7 @@ static int thinking_detect(struct psmouse *psmouse, int set_properties)
 /*
  * Bare PS/2 protocol "detection". Always succeeds.
  */
-static int ps2bare_detect(struct psmouse *psmouse, int set_properties)
+static int ps2bare_detect(struct psmouse *psmouse, bool set_properties)
 {
        if (set_properties) {
                if (!psmouse->vendor) psmouse->vendor = "Generic";
@@ -561,12 +562,12 @@ static int ps2bare_detect(struct psmouse *psmouse, int set_properties)
  * Cortron PS/2 protocol detection. There's no special way to detect it, so it
  * must be forced by sysfs protocol writing.
  */
-static int cortron_detect(struct psmouse *psmouse, int set_properties)
+static int cortron_detect(struct psmouse *psmouse, bool set_properties)
 {
        if (set_properties) {
                psmouse->vendor = "Cortron";
                psmouse->name = "PS/2 Trackball";
-               set_bit(BTN_SIDE, psmouse->dev->keybit);
+               __set_bit(BTN_SIDE, psmouse->dev->keybit);
        }
 
        return 0;
@@ -578,9 +579,9 @@ static int cortron_detect(struct psmouse *psmouse, int set_properties)
  */
 
 static int psmouse_extensions(struct psmouse *psmouse,
-                             unsigned int max_proto, int set_properties)
+                             unsigned int max_proto, bool set_properties)
 {
-       int synaptics_hardware = 0;
+       bool synaptics_hardware = true;
 
 /*
  * We always check for lifebook because it does not disturb mouse
@@ -607,7 +608,7 @@ static int psmouse_extensions(struct psmouse *psmouse,
  * can reset it properly after probing for intellimouse.
  */
        if (max_proto > PSMOUSE_PS2 && synaptics_detect(psmouse, set_properties) == 0) {
-               synaptics_hardware = 1;
+               synaptics_hardware = true;
 
                if (max_proto > PSMOUSE_IMEX) {
                        if (!set_properties || synaptics_init(psmouse) == 0)
@@ -666,6 +667,20 @@ static int psmouse_extensions(struct psmouse *psmouse,
                max_proto = PSMOUSE_IMEX;
        }
 
+/*
+ * Try Finger Sensing Pad
+ */
+       if (max_proto > PSMOUSE_IMEX) {
+               if (fsp_detect(psmouse, set_properties) == 0) {
+                       if (!set_properties || fsp_init(psmouse) == 0)
+                               return PSMOUSE_FSP;
+/*
+ * Init failed, try basic relative protocols
+ */
+                       max_proto = PSMOUSE_IMEX;
+               }
+       }
+
        if (max_proto > PSMOUSE_IMEX) {
                if (genius_detect(psmouse, set_properties) == 0)
                        return PSMOUSE_GENPS;
@@ -718,7 +733,7 @@ static const struct psmouse_protocol psmouse_protocols[] = {
                .type           = PSMOUSE_PS2,
                .name           = "PS/2",
                .alias          = "bare",
-               .maxproto       = 1,
+               .maxproto       = true,
                .detect         = ps2bare_detect,
        },
 #ifdef CONFIG_MOUSE_PS2_LOGIPS2PP
@@ -745,14 +760,14 @@ static const struct psmouse_protocol psmouse_protocols[] = {
                .type           = PSMOUSE_IMPS,
                .name           = "ImPS/2",
                .alias          = "imps",
-               .maxproto       = 1,
+               .maxproto       = true,
                .detect         = intellimouse_detect,
        },
        {
                .type           = PSMOUSE_IMEX,
                .name           = "ImExPS/2",
                .alias          = "exps",
-               .maxproto       = 1,
+               .maxproto       = true,
                .detect         = im_explorer_detect,
        },
 #ifdef CONFIG_MOUSE_PS2_SYNAPTICS
@@ -813,7 +828,16 @@ static const struct psmouse_protocol psmouse_protocols[] = {
                .detect         = elantech_detect,
                .init           = elantech_init,
        },
- #endif
+#endif
+#ifdef CONFIG_MOUSE_PS2_SENTELIC
+       {
+               .type           = PSMOUSE_FSP,
+               .name           = "FSPPS/2",
+               .alias          = "fsp",
+               .detect         = fsp_detect,
+               .init           = fsp_init,
+       },
+#endif
        {
                .type           = PSMOUSE_CORTRON,
                .name           = "CortronPS/2",
@@ -824,7 +848,7 @@ static const struct psmouse_protocol psmouse_protocols[] = {
                .type           = PSMOUSE_AUTO,
                .name           = "auto",
                .alias          = "any",
-               .maxproto       = 1,
+               .maxproto       = true,
        },
 };
 
@@ -990,7 +1014,7 @@ static void psmouse_resync(struct work_struct *work)
                container_of(work, struct psmouse, resync_work.work);
        struct serio *serio = psmouse->ps2dev.serio;
        psmouse_ret_t rc = PSMOUSE_GOOD_DATA;
-       int failed = 0, enabled = 0;
+       bool failed = false, enabled = false;
        int i;
 
        mutex_lock(&psmouse_mutex);
@@ -1017,9 +1041,9 @@ static void psmouse_resync(struct work_struct *work)
 
        if (ps2_sendbyte(&psmouse->ps2dev, PSMOUSE_CMD_DISABLE, 20)) {
                if (psmouse->num_resyncs < 3 || psmouse->acks_disable_command)
-                       failed = 1;
+                       failed = true;
        } else
-               psmouse->acks_disable_command = 1;
+               psmouse->acks_disable_command = true;
 
 /*
  * Poll the mouse. If it was reset the packet will be shorter than
@@ -1030,7 +1054,7 @@ static void psmouse_resync(struct work_struct *work)
  */
        if (!failed) {
                if (psmouse->poll(psmouse))
-                       failed = 1;
+                       failed = true;
                else {
                        psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
                        for (i = 0; i < psmouse->pktsize; i++) {
@@ -1040,7 +1064,7 @@ static void psmouse_resync(struct work_struct *work)
                                        break;
                        }
                        if (rc != PSMOUSE_FULL_PACKET)
-                               failed = 1;
+                               failed = true;
                        psmouse_set_state(psmouse, PSMOUSE_RESYNCING);
                }
        }
@@ -1051,7 +1075,7 @@ static void psmouse_resync(struct work_struct *work)
  */
        for (i = 0; i < 5; i++) {
                if (!ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_ENABLE)) {
-                       enabled = 1;
+                       enabled = true;
                        break;
                }
                msleep(200);
@@ -1060,7 +1084,7 @@ static void psmouse_resync(struct work_struct *work)
        if (!enabled) {
                printk(KERN_WARNING "psmouse.c: failed to re-enable mouse on %s\n",
                        psmouse->ps2dev.serio->phys);
-               failed = 1;
+               failed = true;
        }
 
        if (failed) {
@@ -1187,7 +1211,8 @@ static int psmouse_switch_protocol(struct psmouse *psmouse, const struct psmouse
                psmouse->type = proto->type;
        }
        else
-               psmouse->type = psmouse_extensions(psmouse, psmouse_max_proto, 1);
+               psmouse->type = psmouse_extensions(psmouse,
+                                                  psmouse_max_proto, true);
 
        /*
         * If mouse's packet size is 3 there is no point in polling the
@@ -1342,8 +1367,10 @@ static int psmouse_reconnect(struct serio *serio)
                if (psmouse->reconnect(psmouse))
                        goto out;
        } else if (psmouse_probe(psmouse) < 0 ||
-                  psmouse->type != psmouse_extensions(psmouse, psmouse_max_proto, 0))
+                  psmouse->type != psmouse_extensions(psmouse,
+                                               psmouse_max_proto, false)) {
                goto out;
+       }
 
        /* ok, the device type (and capabilities) match the old one,
         * we can continue using it, complete intialization
@@ -1528,7 +1555,9 @@ static ssize_t psmouse_attr_set_protocol(struct psmouse *psmouse, void *data, co
 
        while (serio->child) {
                if (++retry > 3) {
-                       printk(KERN_WARNING "psmouse: failed to destroy child port, protocol change aborted.\n");
+                       printk(KERN_WARNING
+                               "psmouse: failed to destroy child port, "
+                               "protocol change aborted.\n");
                        input_free_device(new_dev);
                        return -EIO;
                }
index 54ed267894bdfaf466a3fc6732bd2252636218b3..e053bdd137ff0c0a61b438571112b17ace545d1c 100644 (file)
@@ -47,10 +47,10 @@ struct psmouse {
        unsigned char pktcnt;
        unsigned char pktsize;
        unsigned char type;
-       unsigned char acks_disable_command;
+       bool acks_disable_command;
        unsigned int model;
        unsigned long last;
-       unsigned long out_of_sync;
+       unsigned long out_of_sync_cnt;
        unsigned long num_resyncs;
        enum psmouse_state state;
        char devname[64];
@@ -60,7 +60,7 @@ struct psmouse {
        unsigned int resolution;
        unsigned int resetafter;
        unsigned int resync_time;
-       unsigned int smartscroll;       /* Logitech only */
+       bool smartscroll;       /* Logitech only */
 
        psmouse_ret_t (*protocol_handler)(struct psmouse *psmouse);
        void (*set_rate)(struct psmouse *psmouse, unsigned int rate);
@@ -91,6 +91,7 @@ enum psmouse_type {
        PSMOUSE_CORTRON,
        PSMOUSE_HGPK,
        PSMOUSE_ELANTECH,
+       PSMOUSE_FSP,
        PSMOUSE_AUTO            /* This one should always be last */
 };
 
@@ -107,7 +108,7 @@ struct psmouse_attribute {
        ssize_t (*show)(struct psmouse *psmouse, void *data, char *buf);
        ssize_t (*set)(struct psmouse *psmouse, void *data,
                        const char *buf, size_t count);
-       int protect;
+       bool protect;
 };
 #define to_psmouse_attr(a)     container_of((a), struct psmouse_attribute, dattr)
 
@@ -116,9 +117,7 @@ ssize_t psmouse_attr_show_helper(struct device *dev, struct device_attribute *at
 ssize_t psmouse_attr_set_helper(struct device *dev, struct device_attribute *attr,
                                const char *buf, size_t count);
 
-#define __PSMOUSE_DEFINE_ATTR(_name, _mode, _data, _show, _set, _protect)      \
-static ssize_t _show(struct psmouse *, void *data, char *);                    \
-static ssize_t _set(struct psmouse *, void *data, const char *, size_t);       \
+#define __PSMOUSE_DEFINE_ATTR_VAR(_name, _mode, _data, _show, _set, _protect)  \
 static struct psmouse_attribute psmouse_attr_##_name = {                       \
        .dattr  = {                                                             \
                .attr   = {                                                     \
@@ -134,7 +133,20 @@ static struct psmouse_attribute psmouse_attr_##_name = {                   \
        .protect = _protect,                                                    \
 }
 
-#define PSMOUSE_DEFINE_ATTR(_name, _mode, _data, _show, _set)  \
-               __PSMOUSE_DEFINE_ATTR(_name, _mode, _data, _show, _set, 1)
+#define __PSMOUSE_DEFINE_ATTR(_name, _mode, _data, _show, _set, _protect)      \
+       static ssize_t _show(struct psmouse *, void *, char *);                 \
+       static ssize_t _set(struct psmouse *, void *, const char *, size_t);    \
+       __PSMOUSE_DEFINE_ATTR_VAR(_name, _mode, _data, _show, _set, _protect)
+
+#define PSMOUSE_DEFINE_ATTR(_name, _mode, _data, _show, _set)                  \
+       __PSMOUSE_DEFINE_ATTR(_name, _mode, _data, _show, _set, true)
+
+#define PSMOUSE_DEFINE_RO_ATTR(_name, _mode, _data, _show)                     \
+       static ssize_t _show(struct psmouse *, void *, char *);                 \
+       __PSMOUSE_DEFINE_ATTR_VAR(_name, _mode, _data, _show, NULL, true)
+
+#define PSMOUSE_DEFINE_WO_ATTR(_name, _mode, _data, _set)                      \
+       static ssize_t _set(struct psmouse *, void *, const char *, size_t);    \
+       __PSMOUSE_DEFINE_ATTR_VAR(_name, _mode, _data, NULL, _set, true)
 
 #endif /* _PSMOUSE_H */
diff --git a/drivers/input/mouse/sentelic.c b/drivers/input/mouse/sentelic.c
new file mode 100644 (file)
index 0000000..84e2fc0
--- /dev/null
@@ -0,0 +1,867 @@
+/*-
+ * Finger Sensing Pad PS/2 mouse driver.
+ *
+ * Copyright (C) 2005-2007 Asia Vital Components Co., Ltd.
+ * Copyright (C) 2005-2009 Tai-hwa Liang, Sentelic Corporation.
+ *
+ *   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.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/input.h>
+#include <linux/ctype.h>
+#include <linux/libps2.h>
+#include <linux/serio.h>
+#include <linux/jiffies.h>
+
+#include "psmouse.h"
+#include "sentelic.h"
+
+/*
+ * Timeout for FSP PS/2 command only (in milliseconds).
+ */
+#define        FSP_CMD_TIMEOUT         200
+#define        FSP_CMD_TIMEOUT2        30
+
+/** Driver version. */
+static const char fsp_drv_ver[] = "1.0.0-K";
+
+/*
+ * Make sure that the value being sent to FSP will not conflict with
+ * possible sample rate values.
+ */
+static unsigned char fsp_test_swap_cmd(unsigned char reg_val)
+{
+       switch (reg_val) {
+       case 10: case 20: case 40: case 60: case 80: case 100: case 200:
+               /*
+                * The requested value being sent to FSP matched to possible
+                * sample rates, swap the given value such that the hardware
+                * wouldn't get confused.
+                */
+               return (reg_val >> 4) | (reg_val << 4);
+       default:
+               return reg_val; /* swap isn't necessary */
+       }
+}
+
+/*
+ * Make sure that the value being sent to FSP will not conflict with certain
+ * commands.
+ */
+static unsigned char fsp_test_invert_cmd(unsigned char reg_val)
+{
+       switch (reg_val) {
+       case 0xe9: case 0xee: case 0xf2: case 0xff:
+               /*
+                * The requested value being sent to FSP matched to certain
+                * commands, inverse the given value such that the hardware
+                * wouldn't get confused.
+                */
+               return ~reg_val;
+       default:
+               return reg_val; /* inversion isn't necessary */
+       }
+}
+
+static int fsp_reg_read(struct psmouse *psmouse, int reg_addr, int *reg_val)
+{
+       struct ps2dev *ps2dev = &psmouse->ps2dev;
+       unsigned char param[3];
+       unsigned char addr;
+       int rc = -1;
+
+       /*
+        * We need to shut off the device and switch it into command
+        * mode so we don't confuse our protocol handler. We don't need
+        * to do that for writes because sysfs set helper does this for
+        * us.
+        */
+       ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE);
+       psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
+       mutex_lock(&ps2dev->cmd_mutex);
+
+       if (ps2_sendbyte(ps2dev, 0xf3, FSP_CMD_TIMEOUT) < 0)
+               goto out;
+
+       /* should return 0xfe(request for resending) */
+       ps2_sendbyte(ps2dev, 0x66, FSP_CMD_TIMEOUT2);
+       /* should return 0xfc(failed) */
+       ps2_sendbyte(ps2dev, 0x88, FSP_CMD_TIMEOUT2);
+
+       if (ps2_sendbyte(ps2dev, 0xf3, FSP_CMD_TIMEOUT) < 0)
+               goto out;
+
+       if ((addr = fsp_test_invert_cmd(reg_addr)) != reg_addr) {
+               ps2_sendbyte(ps2dev, 0x68, FSP_CMD_TIMEOUT2);
+       } else if ((addr = fsp_test_swap_cmd(reg_addr)) != reg_addr) {
+               /* swapping is required */
+               ps2_sendbyte(ps2dev, 0xcc, FSP_CMD_TIMEOUT2);
+               /* expect 0xfe */
+       } else {
+               /* swapping isn't necessary */
+               ps2_sendbyte(ps2dev, 0x66, FSP_CMD_TIMEOUT2);
+               /* expect 0xfe */
+       }
+       /* should return 0xfc(failed) */
+       ps2_sendbyte(ps2dev, addr, FSP_CMD_TIMEOUT);
+
+       if (__ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO) < 0)
+               goto out;
+
+       *reg_val = param[2];
+       rc = 0;
+
+ out:
+       mutex_unlock(&ps2dev->cmd_mutex);
+       ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE);
+       psmouse_set_state(psmouse, PSMOUSE_ACTIVATED);
+       dev_dbg(&ps2dev->serio->dev, "READ REG: 0x%02x is 0x%02x (rc = %d)\n",
+               reg_addr, *reg_val, rc);
+       return rc;
+}
+
+static int fsp_reg_write(struct psmouse *psmouse, int reg_addr, int reg_val)
+{
+       struct ps2dev *ps2dev = &psmouse->ps2dev;
+       unsigned char v;
+       int rc = -1;
+
+       mutex_lock(&ps2dev->cmd_mutex);
+
+       if (ps2_sendbyte(ps2dev, 0xf3, FSP_CMD_TIMEOUT) < 0)
+               goto out;
+
+       if ((v = fsp_test_invert_cmd(reg_addr)) != reg_addr) {
+               /* inversion is required */
+               ps2_sendbyte(ps2dev, 0x74, FSP_CMD_TIMEOUT2);
+       } else {
+               if ((v = fsp_test_swap_cmd(reg_addr)) != reg_addr) {
+                       /* swapping is required */
+                       ps2_sendbyte(ps2dev, 0x77, FSP_CMD_TIMEOUT2);
+               } else {
+                       /* swapping isn't necessary */
+                       ps2_sendbyte(ps2dev, 0x55, FSP_CMD_TIMEOUT2);
+               }
+       }
+       /* write the register address in correct order */
+       ps2_sendbyte(ps2dev, v, FSP_CMD_TIMEOUT2);
+
+       if (ps2_sendbyte(ps2dev, 0xf3, FSP_CMD_TIMEOUT) < 0)
+               return -1;
+
+       if ((v = fsp_test_invert_cmd(reg_val)) != reg_val) {
+               /* inversion is required */
+               ps2_sendbyte(ps2dev, 0x47, FSP_CMD_TIMEOUT2);
+       } else if ((v = fsp_test_swap_cmd(reg_val)) != reg_val) {
+               /* swapping is required */
+               ps2_sendbyte(ps2dev, 0x44, FSP_CMD_TIMEOUT2);
+       } else {
+               /* swapping isn't necessary */
+               ps2_sendbyte(ps2dev, 0x33, FSP_CMD_TIMEOUT2);
+       }
+
+       /* write the register value in correct order */
+       ps2_sendbyte(ps2dev, v, FSP_CMD_TIMEOUT2);
+       rc = 0;
+
+ out:
+       mutex_unlock(&ps2dev->cmd_mutex);
+       dev_dbg(&ps2dev->serio->dev, "WRITE REG: 0x%02x to 0x%02x (rc = %d)\n",
+               reg_addr, reg_val, rc);
+       return rc;
+}
+
+/* Enable register clock gating for writing certain registers */
+static int fsp_reg_write_enable(struct psmouse *psmouse, bool enable)
+{
+       int v, nv;
+
+       if (fsp_reg_read(psmouse, FSP_REG_SYSCTL1, &v) == -1)
+               return -1;
+
+       if (enable)
+               nv = v | FSP_BIT_EN_REG_CLK;
+       else
+               nv = v & ~FSP_BIT_EN_REG_CLK;
+
+       /* only write if necessary */
+       if (nv != v)
+               if (fsp_reg_write(psmouse, FSP_REG_SYSCTL1, nv) == -1)
+                       return -1;
+
+       return 0;
+}
+
+static int fsp_page_reg_read(struct psmouse *psmouse, int *reg_val)
+{
+       struct ps2dev *ps2dev = &psmouse->ps2dev;
+       unsigned char param[3];
+       int rc = -1;
+
+       ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE);
+       psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
+       mutex_lock(&ps2dev->cmd_mutex);
+
+       if (ps2_sendbyte(ps2dev, 0xf3, FSP_CMD_TIMEOUT) < 0)
+               goto out;
+
+       ps2_sendbyte(ps2dev, 0x66, FSP_CMD_TIMEOUT2);
+       ps2_sendbyte(ps2dev, 0x88, FSP_CMD_TIMEOUT2);
+
+       if (ps2_sendbyte(ps2dev, 0xf3, FSP_CMD_TIMEOUT) < 0)
+               goto out;
+
+       ps2_sendbyte(ps2dev, 0x83, FSP_CMD_TIMEOUT2);
+       ps2_sendbyte(ps2dev, 0x88, FSP_CMD_TIMEOUT2);
+
+       /* get the returned result */
+       if (__ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO))
+               goto out;
+
+       *reg_val = param[2];
+       rc = 0;
+
+ out:
+       mutex_unlock(&ps2dev->cmd_mutex);
+       ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE);
+       psmouse_set_state(psmouse, PSMOUSE_ACTIVATED);
+       dev_dbg(&ps2dev->serio->dev, "READ PAGE REG: 0x%02x (rc = %d)\n",
+               *reg_val, rc);
+       return rc;
+}
+
+static int fsp_page_reg_write(struct psmouse *psmouse, int reg_val)
+{
+       struct ps2dev *ps2dev = &psmouse->ps2dev;
+       unsigned char v;
+       int rc = -1;
+
+       mutex_lock(&ps2dev->cmd_mutex);
+
+       if (ps2_sendbyte(ps2dev, 0xf3, FSP_CMD_TIMEOUT) < 0)
+               goto out;
+
+       ps2_sendbyte(ps2dev, 0x38, FSP_CMD_TIMEOUT2);
+       ps2_sendbyte(ps2dev, 0x88, FSP_CMD_TIMEOUT2);
+
+       if (ps2_sendbyte(ps2dev, 0xf3, FSP_CMD_TIMEOUT) < 0)
+               return -1;
+
+       if ((v = fsp_test_invert_cmd(reg_val)) != reg_val) {
+               ps2_sendbyte(ps2dev, 0x47, FSP_CMD_TIMEOUT2);
+       } else if ((v = fsp_test_swap_cmd(reg_val)) != reg_val) {
+               /* swapping is required */
+               ps2_sendbyte(ps2dev, 0x44, FSP_CMD_TIMEOUT2);
+       } else {
+               /* swapping isn't necessary */
+               ps2_sendbyte(ps2dev, 0x33, FSP_CMD_TIMEOUT2);
+       }
+
+       ps2_sendbyte(ps2dev, v, FSP_CMD_TIMEOUT2);
+       rc = 0;
+
+ out:
+       mutex_unlock(&ps2dev->cmd_mutex);
+       dev_dbg(&ps2dev->serio->dev, "WRITE PAGE REG: to 0x%02x (rc = %d)\n",
+               reg_val, rc);
+       return rc;
+}
+
+static int fsp_get_version(struct psmouse *psmouse, int *version)
+{
+       if (fsp_reg_read(psmouse, FSP_REG_VERSION, version))
+               return -EIO;
+
+       return 0;
+}
+
+static int fsp_get_revision(struct psmouse *psmouse, int *rev)
+{
+       if (fsp_reg_read(psmouse, FSP_REG_REVISION, rev))
+               return -EIO;
+
+       return 0;
+}
+
+static int fsp_get_buttons(struct psmouse *psmouse, int *btn)
+{
+       static const int buttons[] = {
+               0x16, /* Left/Middle/Right/Forward/Backward & Scroll Up/Down */
+               0x06, /* Left/Middle/Right & Scroll Up/Down/Right/Left */
+               0x04, /* Left/Middle/Right & Scroll Up/Down */
+               0x02, /* Left/Middle/Right */
+       };
+       int val;
+
+       if (fsp_reg_read(psmouse, FSP_REG_TMOD_STATUS1, &val) == -1)
+               return -EIO;
+
+       *btn = buttons[(val & 0x30) >> 4];
+       return 0;
+}
+
+/* Enable on-pad command tag output */
+static int fsp_opc_tag_enable(struct psmouse *psmouse, bool enable)
+{
+       int v, nv;
+       int res = 0;
+
+       if (fsp_reg_read(psmouse, FSP_REG_OPC_QDOWN, &v) == -1) {
+               dev_err(&psmouse->ps2dev.serio->dev, "Unable get OPC state.\n");
+               return -EIO;
+       }
+
+       if (enable)
+               nv = v | FSP_BIT_EN_OPC_TAG;
+       else
+               nv = v & ~FSP_BIT_EN_OPC_TAG;
+
+       /* only write if necessary */
+       if (nv != v) {
+               fsp_reg_write_enable(psmouse, true);
+               res = fsp_reg_write(psmouse, FSP_REG_OPC_QDOWN, nv);
+               fsp_reg_write_enable(psmouse, false);
+       }
+
+       if (res != 0) {
+               dev_err(&psmouse->ps2dev.serio->dev,
+                       "Unable to enable OPC tag.\n");
+               res = -EIO;
+       }
+
+       return res;
+}
+
+static int fsp_onpad_vscr(struct psmouse *psmouse, bool enable)
+{
+       struct fsp_data *pad = psmouse->private;
+       int val;
+
+       if (fsp_reg_read(psmouse, FSP_REG_ONPAD_CTL, &val))
+               return -EIO;
+
+       pad->vscroll = enable;
+
+       if (enable)
+               val |= (FSP_BIT_FIX_VSCR | FSP_BIT_ONPAD_ENABLE);
+       else
+               val &= ~FSP_BIT_FIX_VSCR;
+
+       if (fsp_reg_write(psmouse, FSP_REG_ONPAD_CTL, val))
+               return -EIO;
+
+       return 0;
+}
+
+static int fsp_onpad_hscr(struct psmouse *psmouse, bool enable)
+{
+       struct fsp_data *pad = psmouse->private;
+       int val, v2;
+
+       if (fsp_reg_read(psmouse, FSP_REG_ONPAD_CTL, &val))
+               return -EIO;
+
+       if (fsp_reg_read(psmouse, FSP_REG_SYSCTL5, &v2))
+               return -EIO;
+
+       pad->hscroll = enable;
+
+       if (enable) {
+               val |= (FSP_BIT_FIX_HSCR | FSP_BIT_ONPAD_ENABLE);
+               v2 |= FSP_BIT_EN_MSID6;
+       } else {
+               val &= ~FSP_BIT_FIX_HSCR;
+               v2 &= ~(FSP_BIT_EN_MSID6 | FSP_BIT_EN_MSID7 | FSP_BIT_EN_MSID8);
+       }
+
+       if (fsp_reg_write(psmouse, FSP_REG_ONPAD_CTL, val))
+               return -EIO;
+
+       /* reconfigure horizontal scrolling packet output */
+       if (fsp_reg_write(psmouse, FSP_REG_SYSCTL5, v2))
+               return -EIO;
+
+       return 0;
+}
+
+/*
+ * Write device specific initial parameters.
+ *
+ * ex: 0xab 0xcd - write oxcd into register 0xab
+ */
+static ssize_t fsp_attr_set_setreg(struct psmouse *psmouse, void *data,
+                                  const char *buf, size_t count)
+{
+       unsigned long reg, val;
+       char *rest;
+       ssize_t retval;
+
+       reg = simple_strtoul(buf, &rest, 16);
+       if (rest == buf || *rest != ' ' || reg > 0xff)
+               return -EINVAL;
+
+       if (strict_strtoul(rest + 1, 16, &val) || val > 0xff)
+               return -EINVAL;
+
+       if (fsp_reg_write_enable(psmouse, true))
+               return -EIO;
+
+       retval = fsp_reg_write(psmouse, reg, val) < 0 ? -EIO : count;
+
+       fsp_reg_write_enable(psmouse, false);
+
+       return count;
+}
+
+PSMOUSE_DEFINE_WO_ATTR(setreg, S_IWUSR, NULL, fsp_attr_set_setreg);
+
+static ssize_t fsp_attr_show_getreg(struct psmouse *psmouse,
+                                       void *data, char *buf)
+{
+       struct fsp_data *pad = psmouse->private;
+
+       return sprintf(buf, "%02x%02x\n", pad->last_reg, pad->last_val);
+}
+
+/*
+ * Read a register from device.
+ *
+ * ex: 0xab -- read content from register 0xab
+ */
+static ssize_t fsp_attr_set_getreg(struct psmouse *psmouse, void *data,
+                                       const char *buf, size_t count)
+{
+       struct fsp_data *pad = psmouse->private;
+       unsigned long reg;
+       int val;
+
+       if (strict_strtoul(buf, 16, &reg) || reg > 0xff)
+               return -EINVAL;
+
+       if (fsp_reg_read(psmouse, reg, &val))
+               return -EIO;
+
+       pad->last_reg = reg;
+       pad->last_val = val;
+
+       return count;
+}
+
+PSMOUSE_DEFINE_ATTR(getreg, S_IWUSR | S_IRUGO, NULL,
+                       fsp_attr_show_getreg, fsp_attr_set_getreg);
+
+static ssize_t fsp_attr_show_pagereg(struct psmouse *psmouse,
+                                       void *data, char *buf)
+{
+       int val = 0;
+
+       if (fsp_page_reg_read(psmouse, &val))
+               return -EIO;
+
+       return sprintf(buf, "%02x\n", val);
+}
+
+static ssize_t fsp_attr_set_pagereg(struct psmouse *psmouse, void *data,
+                                       const char *buf, size_t count)
+{
+       unsigned long val;
+
+       if (strict_strtoul(buf, 16, &val) || val > 0xff)
+               return -EINVAL;
+
+       if (fsp_page_reg_write(psmouse, val))
+               return -EIO;
+
+       return count;
+}
+
+PSMOUSE_DEFINE_ATTR(page, S_IWUSR | S_IRUGO, NULL,
+                       fsp_attr_show_pagereg, fsp_attr_set_pagereg);
+
+static ssize_t fsp_attr_show_vscroll(struct psmouse *psmouse,
+                                       void *data, char *buf)
+{
+       struct fsp_data *pad = psmouse->private;
+
+       return sprintf(buf, "%d\n", pad->vscroll);
+}
+
+static ssize_t fsp_attr_set_vscroll(struct psmouse *psmouse, void *data,
+                                       const char *buf, size_t count)
+{
+       unsigned long val;
+
+       if (strict_strtoul(buf, 10, &val) || val > 1)
+               return -EINVAL;
+
+       fsp_onpad_vscr(psmouse, val);
+
+       return count;
+}
+
+PSMOUSE_DEFINE_ATTR(vscroll, S_IWUSR | S_IRUGO, NULL,
+                       fsp_attr_show_vscroll, fsp_attr_set_vscroll);
+
+static ssize_t fsp_attr_show_hscroll(struct psmouse *psmouse,
+                                       void *data, char *buf)
+{
+       struct fsp_data *pad = psmouse->private;
+
+       return sprintf(buf, "%d\n", pad->hscroll);
+}
+
+static ssize_t fsp_attr_set_hscroll(struct psmouse *psmouse, void *data,
+                                       const char *buf, size_t count)
+{
+       unsigned long val;
+
+       if (strict_strtoul(buf, 10, &val) || val > 1)
+               return -EINVAL;
+
+       fsp_onpad_hscr(psmouse, val);
+
+       return count;
+}
+
+PSMOUSE_DEFINE_ATTR(hscroll, S_IWUSR | S_IRUGO, NULL,
+                       fsp_attr_show_hscroll, fsp_attr_set_hscroll);
+
+static ssize_t fsp_attr_show_flags(struct psmouse *psmouse,
+                                       void *data, char *buf)
+{
+       struct fsp_data *pad = psmouse->private;
+
+       return sprintf(buf, "%c\n",
+                       pad->flags & FSPDRV_FLAG_EN_OPC ? 'C' : 'c');
+}
+
+static ssize_t fsp_attr_set_flags(struct psmouse *psmouse, void *data,
+                                       const char *buf, size_t count)
+{
+       struct fsp_data *pad = psmouse->private;
+       size_t i;
+
+       for (i = 0; i < count; i++) {
+               switch (buf[i]) {
+               case 'C':
+                       pad->flags |= FSPDRV_FLAG_EN_OPC;
+                       break;
+               case 'c':
+                       pad->flags &= ~FSPDRV_FLAG_EN_OPC;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+       }
+       return count;
+}
+
+PSMOUSE_DEFINE_ATTR(flags, S_IWUSR | S_IRUGO, NULL,
+                       fsp_attr_show_flags, fsp_attr_set_flags);
+
+static ssize_t fsp_attr_show_ver(struct psmouse *psmouse,
+                                       void *data, char *buf)
+{
+       return sprintf(buf, "Sentelic FSP kernel module %s\n", fsp_drv_ver);
+}
+
+PSMOUSE_DEFINE_RO_ATTR(ver, S_IRUGO, NULL, fsp_attr_show_ver);
+
+static struct attribute *fsp_attributes[] = {
+       &psmouse_attr_setreg.dattr.attr,
+       &psmouse_attr_getreg.dattr.attr,
+       &psmouse_attr_page.dattr.attr,
+       &psmouse_attr_vscroll.dattr.attr,
+       &psmouse_attr_hscroll.dattr.attr,
+       &psmouse_attr_flags.dattr.attr,
+       &psmouse_attr_ver.dattr.attr,
+       NULL
+};
+
+static struct attribute_group fsp_attribute_group = {
+       .attrs = fsp_attributes,
+};
+
+#ifdef FSP_DEBUG
+static void fsp_packet_debug(unsigned char packet[])
+{
+       static unsigned int ps2_packet_cnt;
+       static unsigned int ps2_last_second;
+       unsigned int jiffies_msec;
+
+       ps2_packet_cnt++;
+       jiffies_msec = jiffies_to_msecs(jiffies);
+       printk(KERN_DEBUG "%08dms PS/2 packets: %02x, %02x, %02x, %02x\n",
+               jiffies_msec, packet[0], packet[1], packet[2], packet[3]);
+
+       if (jiffies_msec - ps2_last_second > 1000) {
+               printk(KERN_DEBUG "PS/2 packets/sec = %d\n", ps2_packet_cnt);
+               ps2_packet_cnt = 0;
+               ps2_last_second = jiffies_msec;
+       }
+}
+#else
+static void fsp_packet_debug(unsigned char packet[])
+{
+}
+#endif
+
+static psmouse_ret_t fsp_process_byte(struct psmouse *psmouse)
+{
+       struct input_dev *dev = psmouse->dev;
+       struct fsp_data *ad = psmouse->private;
+       unsigned char *packet = psmouse->packet;
+       unsigned char button_status = 0, lscroll = 0, rscroll = 0;
+       int rel_x, rel_y;
+
+       if (psmouse->pktcnt < 4)
+               return PSMOUSE_GOOD_DATA;
+
+       /*
+        * Full packet accumulated, process it
+        */
+
+       switch (psmouse->packet[0] >> FSP_PKT_TYPE_SHIFT) {
+       case FSP_PKT_TYPE_ABS:
+               dev_warn(&psmouse->ps2dev.serio->dev,
+                        "Unexpected absolute mode packet, ignored.\n");
+               break;
+
+       case FSP_PKT_TYPE_NORMAL_OPC:
+               /* on-pad click, filter it if necessary */
+               if ((ad->flags & FSPDRV_FLAG_EN_OPC) != FSPDRV_FLAG_EN_OPC)
+                       packet[0] &= ~BIT(0);
+               /* fall through */
+
+       case FSP_PKT_TYPE_NORMAL:
+               /* normal packet */
+               /* special packet data translation from on-pad packets */
+               if (packet[3] != 0) {
+                       if (packet[3] & BIT(0))
+                               button_status |= 0x01;  /* wheel down */
+                       if (packet[3] & BIT(1))
+                               button_status |= 0x0f;  /* wheel up */
+                       if (packet[3] & BIT(2))
+                               button_status |= BIT(5);/* horizontal left */
+                       if (packet[3] & BIT(3))
+                               button_status |= BIT(4);/* horizontal right */
+                       /* push back to packet queue */
+                       if (button_status != 0)
+                               packet[3] = button_status;
+                       rscroll = (packet[3] >> 4) & 1;
+                       lscroll = (packet[3] >> 5) & 1;
+               }
+               /*
+                * Processing wheel up/down and extra button events
+                */
+               input_report_rel(dev, REL_WHEEL,
+                                (int)(packet[3] & 8) - (int)(packet[3] & 7));
+               input_report_rel(dev, REL_HWHEEL, lscroll - rscroll);
+               input_report_key(dev, BTN_BACK, lscroll);
+               input_report_key(dev, BTN_FORWARD, rscroll);
+
+               /*
+                * Standard PS/2 Mouse
+                */
+               input_report_key(dev, BTN_LEFT, packet[0] & 1);
+               input_report_key(dev, BTN_MIDDLE, (packet[0] >> 2) & 1);
+               input_report_key(dev, BTN_RIGHT, (packet[0] >> 1) & 1);
+
+               rel_x = packet[1] ? (int)packet[1] - (int)((packet[0] << 4) & 0x100) : 0;
+               rel_y = packet[2] ? (int)((packet[0] << 3) & 0x100) - (int)packet[2] : 0;
+
+               input_report_rel(dev, REL_X, rel_x);
+               input_report_rel(dev, REL_Y, rel_y);
+               break;
+       }
+
+       input_sync(dev);
+
+       fsp_packet_debug(packet);
+
+       return PSMOUSE_FULL_PACKET;
+}
+
+static int fsp_activate_protocol(struct psmouse *psmouse)
+{
+       struct fsp_data *pad = psmouse->private;
+       struct ps2dev *ps2dev = &psmouse->ps2dev;
+       unsigned char param[2];
+       int val;
+
+       /*
+        * Standard procedure to enter FSP Intellimouse mode
+        * (scrolling wheel, 4th and 5th buttons)
+        */
+       param[0] = 200;
+       ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
+       param[0] = 200;
+       ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
+       param[0] =  80;
+       ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
+
+       ps2_command(ps2dev, param, PSMOUSE_CMD_GETID);
+       if (param[0] != 0x04) {
+               dev_err(&psmouse->ps2dev.serio->dev,
+                       "Unable to enable 4 bytes packet format.\n");
+               return -EIO;
+       }
+
+       if (fsp_reg_read(psmouse, FSP_REG_SYSCTL5, &val)) {
+               dev_err(&psmouse->ps2dev.serio->dev,
+                       "Unable to read SYSCTL5 register.\n");
+               return -EIO;
+       }
+
+       val &= ~(FSP_BIT_EN_MSID7 | FSP_BIT_EN_MSID8 | FSP_BIT_EN_AUTO_MSID8);
+       /* Ensure we are not in absolute mode */
+       val &= ~FSP_BIT_EN_PKT_G0;
+       if (pad->buttons == 0x06) {
+               /* Left/Middle/Right & Scroll Up/Down/Right/Left */
+               val |= FSP_BIT_EN_MSID6;
+       }
+
+       if (fsp_reg_write(psmouse, FSP_REG_SYSCTL5, val)) {
+               dev_err(&psmouse->ps2dev.serio->dev,
+                       "Unable to set up required mode bits.\n");
+               return -EIO;
+       }
+
+       /*
+        * Enable OPC tags such that driver can tell the difference between
+        * on-pad and real button click
+        */
+       if (fsp_opc_tag_enable(psmouse, true))
+               dev_warn(&psmouse->ps2dev.serio->dev,
+                        "Failed to enable OPC tag mode.\n");
+
+       /* Enable on-pad vertical and horizontal scrolling */
+       fsp_onpad_vscr(psmouse, true);
+       fsp_onpad_hscr(psmouse, true);
+
+       return 0;
+}
+
+int fsp_detect(struct psmouse *psmouse, bool set_properties)
+{
+       int id;
+
+       if (fsp_reg_read(psmouse, FSP_REG_DEVICE_ID, &id))
+               return -EIO;
+
+       if (id != 0x01)
+               return -ENODEV;
+
+       if (set_properties) {
+               psmouse->vendor = "Sentelic";
+               psmouse->name = "FingerSensingPad";
+       }
+
+       return 0;
+}
+
+static void fsp_reset(struct psmouse *psmouse)
+{
+       fsp_opc_tag_enable(psmouse, false);
+       fsp_onpad_vscr(psmouse, false);
+       fsp_onpad_hscr(psmouse, false);
+}
+
+static void fsp_disconnect(struct psmouse *psmouse)
+{
+       sysfs_remove_group(&psmouse->ps2dev.serio->dev.kobj,
+                          &fsp_attribute_group);
+
+       fsp_reset(psmouse);
+       kfree(psmouse->private);
+}
+
+static int fsp_reconnect(struct psmouse *psmouse)
+{
+       int version;
+
+       if (fsp_detect(psmouse, 0))
+               return -ENODEV;
+
+       if (fsp_get_version(psmouse, &version))
+               return -ENODEV;
+
+       if (fsp_activate_protocol(psmouse))
+               return -EIO;
+
+       return 0;
+}
+
+int fsp_init(struct psmouse *psmouse)
+{
+       struct fsp_data *priv;
+       int ver, rev, buttons;
+       int error;
+
+       if (fsp_get_version(psmouse, &ver) ||
+           fsp_get_revision(psmouse, &rev) ||
+           fsp_get_buttons(psmouse, &buttons)) {
+               return -ENODEV;
+       }
+
+       printk(KERN_INFO
+               "Finger Sensing Pad, hw: %d.%d.%d, sw: %s, buttons: %d\n",
+               ver >> 4, ver & 0x0F, rev, fsp_drv_ver, buttons & 7);
+
+       psmouse->private = priv = kzalloc(sizeof(struct fsp_data), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       priv->ver = ver;
+       priv->rev = rev;
+       priv->buttons = buttons;
+
+       /* enable on-pad click by default */
+       priv->flags |= FSPDRV_FLAG_EN_OPC;
+
+       /* Set up various supported input event bits */
+       __set_bit(BTN_BACK, psmouse->dev->keybit);
+       __set_bit(BTN_FORWARD, psmouse->dev->keybit);
+       __set_bit(REL_WHEEL, psmouse->dev->relbit);
+       __set_bit(REL_HWHEEL, psmouse->dev->relbit);
+
+       psmouse->protocol_handler = fsp_process_byte;
+       psmouse->disconnect = fsp_disconnect;
+       psmouse->reconnect = fsp_reconnect;
+       psmouse->cleanup = fsp_reset;
+       psmouse->pktsize = 4;
+
+       /* set default packet output based on number of buttons we found */
+       error = fsp_activate_protocol(psmouse);
+       if (error)
+               goto err_out;
+
+       error = sysfs_create_group(&psmouse->ps2dev.serio->dev.kobj,
+                                  &fsp_attribute_group);
+       if (error) {
+               dev_err(&psmouse->ps2dev.serio->dev,
+                       "Failed to create sysfs attributes (%d)", error);
+               goto err_out;
+       }
+
+       return 0;
+
+ err_out:
+       kfree(psmouse->private);
+       psmouse->private = NULL;
+       return error;
+}
diff --git a/drivers/input/mouse/sentelic.h b/drivers/input/mouse/sentelic.h
new file mode 100644 (file)
index 0000000..ed1395a
--- /dev/null
@@ -0,0 +1,98 @@
+/*-
+ * Finger Sensing Pad PS/2 mouse driver.
+ *
+ * Copyright (C) 2005-2007 Asia Vital Components Co., Ltd.
+ * Copyright (C) 2005-2009 Tai-hwa Liang, Sentelic Corporation.
+ *
+ *   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.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef        __SENTELIC_H
+#define        __SENTELIC_H
+
+/* Finger-sensing Pad information registers */
+#define        FSP_REG_DEVICE_ID       0x00
+#define        FSP_REG_VERSION         0x01
+#define        FSP_REG_REVISION        0x04
+#define        FSP_REG_TMOD_STATUS1    0x0B
+#define        FSP_BIT_NO_ROTATION     BIT(3)
+#define        FSP_REG_PAGE_CTRL       0x0F
+
+/* Finger-sensing Pad control registers */
+#define        FSP_REG_SYSCTL1         0x10
+#define        FSP_BIT_EN_REG_CLK      BIT(5)
+#define        FSP_REG_OPC_QDOWN       0x31
+#define        FSP_BIT_EN_OPC_TAG      BIT(7)
+#define        FSP_REG_OPTZ_XLO        0x34
+#define        FSP_REG_OPTZ_XHI        0x35
+#define        FSP_REG_OPTZ_YLO        0x36
+#define        FSP_REG_OPTZ_YHI        0x37
+#define        FSP_REG_SYSCTL5         0x40
+#define        FSP_BIT_90_DEGREE       BIT(0)
+#define        FSP_BIT_EN_MSID6        BIT(1)
+#define        FSP_BIT_EN_MSID7        BIT(2)
+#define        FSP_BIT_EN_MSID8        BIT(3)
+#define        FSP_BIT_EN_AUTO_MSID8   BIT(5)
+#define        FSP_BIT_EN_PKT_G0       BIT(6)
+
+#define        FSP_REG_ONPAD_CTL       0x43
+#define        FSP_BIT_ONPAD_ENABLE    BIT(0)
+#define        FSP_BIT_ONPAD_FBBB      BIT(1)
+#define        FSP_BIT_FIX_VSCR        BIT(3)
+#define        FSP_BIT_FIX_HSCR        BIT(5)
+#define        FSP_BIT_DRAG_LOCK       BIT(6)
+
+/* Finger-sensing Pad packet formating related definitions */
+
+/* absolute packet type */
+#define        FSP_PKT_TYPE_NORMAL     (0x00)
+#define        FSP_PKT_TYPE_ABS        (0x01)
+#define        FSP_PKT_TYPE_NOTIFY     (0x02)
+#define        FSP_PKT_TYPE_NORMAL_OPC (0x03)
+#define        FSP_PKT_TYPE_SHIFT      (6)
+
+#ifdef __KERNEL__
+
+struct fsp_data {
+       unsigned char   ver;            /* hardware version */
+       unsigned char   rev;            /* hardware revison */
+       unsigned char   buttons;        /* Number of buttons */
+       unsigned int    flags;
+#define        FSPDRV_FLAG_EN_OPC      (0x001) /* enable on-pad clicking */
+
+       bool            vscroll;        /* Vertical scroll zone enabled */
+       bool            hscroll;        /* Horizontal scroll zone enabled */
+
+       unsigned char   last_reg;       /* Last register we requested read from */
+       unsigned char   last_val;
+};
+
+#ifdef CONFIG_MOUSE_PS2_SENTELIC
+extern int fsp_detect(struct psmouse *psmouse, bool set_properties);
+extern int fsp_init(struct psmouse *psmouse);
+#else
+inline int fsp_detect(struct psmouse *psmouse, bool set_properties)
+{
+       return -ENOSYS;
+}
+inline int fsp_init(struct psmouse *psmouse)
+{
+       return -ENOSYS;
+}
+#endif
+
+#endif /* __KERNEL__ */
+
+#endif /* !__SENTELIC_H */
index 19984bf06cad8b79b91783df1fe1102d48a61177..b66ff1ac7dea651ebbfc263dc83774168f5f9ae5 100644 (file)
@@ -60,7 +60,7 @@ static int synaptics_mode_cmd(struct psmouse *psmouse, unsigned char mode)
        return 0;
 }
 
-int synaptics_detect(struct psmouse *psmouse, int set_properties)
+int synaptics_detect(struct psmouse *psmouse, bool set_properties)
 {
        struct ps2dev *ps2dev = &psmouse->ps2dev;
        unsigned char param[4];
@@ -556,38 +556,38 @@ static void set_input_params(struct input_dev *dev, struct synaptics_data *priv)
 {
        int i;
 
-       set_bit(EV_ABS, dev->evbit);
+       __set_bit(EV_ABS, dev->evbit);
        input_set_abs_params(dev, ABS_X, XMIN_NOMINAL, XMAX_NOMINAL, 0, 0);
        input_set_abs_params(dev, ABS_Y, YMIN_NOMINAL, YMAX_NOMINAL, 0, 0);
        input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0);
-       set_bit(ABS_TOOL_WIDTH, dev->absbit);
+       __set_bit(ABS_TOOL_WIDTH, dev->absbit);
 
-       set_bit(EV_KEY, dev->evbit);
-       set_bit(BTN_TOUCH, dev->keybit);
-       set_bit(BTN_TOOL_FINGER, dev->keybit);
-       set_bit(BTN_LEFT, dev->keybit);
-       set_bit(BTN_RIGHT, dev->keybit);
+       __set_bit(EV_KEY, dev->evbit);
+       __set_bit(BTN_TOUCH, dev->keybit);
+       __set_bit(BTN_TOOL_FINGER, dev->keybit);
+       __set_bit(BTN_LEFT, dev->keybit);
+       __set_bit(BTN_RIGHT, dev->keybit);
 
        if (SYN_CAP_MULTIFINGER(priv->capabilities)) {
-               set_bit(BTN_TOOL_DOUBLETAP, dev->keybit);
-               set_bit(BTN_TOOL_TRIPLETAP, dev->keybit);
+               __set_bit(BTN_TOOL_DOUBLETAP, dev->keybit);
+               __set_bit(BTN_TOOL_TRIPLETAP, dev->keybit);
        }
 
        if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities))
-               set_bit(BTN_MIDDLE, dev->keybit);
+               __set_bit(BTN_MIDDLE, dev->keybit);
 
        if (SYN_CAP_FOUR_BUTTON(priv->capabilities) ||
            SYN_CAP_MIDDLE_BUTTON(priv->capabilities)) {
-               set_bit(BTN_FORWARD, dev->keybit);
-               set_bit(BTN_BACK, dev->keybit);
+               __set_bit(BTN_FORWARD, dev->keybit);
+               __set_bit(BTN_BACK, dev->keybit);
        }
 
        for (i = 0; i < SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap); i++)
-               set_bit(BTN_0 + i, dev->keybit);
+               __set_bit(BTN_0 + i, dev->keybit);
 
-       clear_bit(EV_REL, dev->evbit);
-       clear_bit(REL_X, dev->relbit);
-       clear_bit(REL_Y, dev->relbit);
+       __clear_bit(EV_REL, dev->evbit);
+       __clear_bit(REL_X, dev->relbit);
+       __clear_bit(REL_Y, dev->relbit);
 
        dev->absres[ABS_X] = priv->x_res;
        dev->absres[ABS_Y] = priv->y_res;
index 3023821517523c354299cb7cfcd5c8e1e4de837c..871f6fe377f941d263cd93d9abc237ae7f29714d 100644 (file)
@@ -105,7 +105,7 @@ struct synaptics_data {
        int scroll;
 };
 
-int synaptics_detect(struct psmouse *psmouse, int set_properties);
+int synaptics_detect(struct psmouse *psmouse, bool set_properties);
 int synaptics_init(struct psmouse *psmouse);
 void synaptics_reset(struct psmouse *psmouse);
 
index 3fadb2accac0264baa3dc2790241fd5e4ae1783a..0308a0faa94d5ee7944be9ee412c37fadb5f67d5 100644 (file)
@@ -67,7 +67,7 @@ static psmouse_ret_t touchkit_ps2_process_byte(struct psmouse *psmouse)
        return PSMOUSE_FULL_PACKET;
 }
 
-int touchkit_ps2_detect(struct psmouse *psmouse, int set_properties)
+int touchkit_ps2_detect(struct psmouse *psmouse, bool set_properties)
 {
        struct input_dev *dev = psmouse->dev;
        unsigned char param[3];
@@ -86,7 +86,7 @@ int touchkit_ps2_detect(struct psmouse *psmouse, int set_properties)
 
        if (set_properties) {
                dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
-               set_bit(BTN_TOUCH, dev->keybit);
+               __set_bit(BTN_TOUCH, dev->keybit);
                input_set_abs_params(dev, ABS_X, 0, TOUCHKIT_MAX_XC, 0, 0);
                input_set_abs_params(dev, ABS_Y, 0, TOUCHKIT_MAX_YC, 0, 0);
 
index 8a0dd3574aefb0a9d11913728e2cbe02ebc95e13..2efe9ea29d0c65eb0fa38797a4181bea41fc2a47 100644 (file)
 #define _TOUCHKIT_PS2_H
 
 #ifdef CONFIG_MOUSE_PS2_TOUCHKIT
-int touchkit_ps2_detect(struct psmouse *psmouse, int set_properties);
+int touchkit_ps2_detect(struct psmouse *psmouse, bool set_properties);
 #else
 static inline int touchkit_ps2_detect(struct psmouse *psmouse,
-                                     int set_properties)
+                                     bool set_properties)
 {
        return -ENOSYS;
 }
index e68c814c43612f449d4b9976a1cc45fbb7445efd..e354362f29718a932cb1208501c94d4c8d88c34c 100644 (file)
@@ -282,7 +282,7 @@ static int trackpoint_reconnect(struct psmouse *psmouse)
        return 0;
 }
 
-int trackpoint_detect(struct psmouse *psmouse, int set_properties)
+int trackpoint_detect(struct psmouse *psmouse, bool set_properties)
 {
        struct trackpoint_data *priv;
        struct ps2dev *ps2dev = &psmouse->ps2dev;
index c10a6e7d01011bdfa6bbceb16fcf0cddb72dc3ce..e558a7096618a36cea0ad9a555f2056883b12ca7 100644 (file)
@@ -143,9 +143,9 @@ struct trackpoint_data
 };
 
 #ifdef CONFIG_MOUSE_PS2_TRACKPOINT
-int trackpoint_detect(struct psmouse *psmouse, int set_properties);
+int trackpoint_detect(struct psmouse *psmouse, bool set_properties);
 #else
-inline int trackpoint_detect(struct psmouse *psmouse, int set_properties)
+inline int trackpoint_detect(struct psmouse *psmouse, bool set_properties)
 {
        return -ENOSYS;
 }
index 404eedd5ffa2b7e039db5c7508971450e7ae1a4c..70111443678eac830d783c67e89e5516989b70bf 100644 (file)
@@ -384,11 +384,11 @@ vsxxxaa_handle_POR_packet (struct vsxxxaa *mouse)
        printk (KERN_NOTICE "%s on %s: Forceing standard packet format, "
                        "incremental streaming mode and 72 samples/sec\n",
                        mouse->name, mouse->phys);
-       mouse->serio->write (mouse->serio, 'S');        /* Standard format */
+       serio_write (mouse->serio, 'S');        /* Standard format */
        mdelay (50);
-       mouse->serio->write (mouse->serio, 'R');        /* Incremental */
+       serio_write (mouse->serio, 'R');        /* Incremental */
        mdelay (50);
-       mouse->serio->write (mouse->serio, 'L');        /* 72 samples/sec */
+       serio_write (mouse->serio, 'L');        /* 72 samples/sec */
 }
 
 static void
@@ -532,7 +532,7 @@ vsxxxaa_connect (struct serio *serio, struct serio_driver *drv)
         * Request selftest. Standard packet format and differential
         * mode will be requested after the device ID'ed successfully.
         */
-       serio->write (serio, 'T'); /* Test */
+       serio_write (serio, 'T'); /* Test */
 
        err = input_register_device (input_dev);
        if (err)
index 41fda8c67b1ead39b9a317bf18f6c7ac0f8d0556..a6fb7a3dcc46bca0b3770fd89ef2e1fd94e55b84 100644 (file)
@@ -231,7 +231,7 @@ static int __init psif_probe(struct platform_device *pdev)
                goto out_free_io;
        }
 
-       psif->regs = ioremap(regs->start, regs->end - regs->start + 1);
+       psif->regs = ioremap(regs->start, resource_size(regs));
        if (!psif->regs) {
                ret = -ENOMEM;
                dev_dbg(&pdev->dev, "could not map I/O memory\n");
index ccbf23ece8e370cc2e59fa4fef47d8cfd9ed5a09..a39bc4eb902b642cbbb897550519c7bfc53ddcc1 100644 (file)
@@ -457,6 +457,34 @@ static struct dmi_system_id __initdata i8042_dmi_nopnp_table[] = {
        },
        { }
 };
+
+static struct dmi_system_id __initdata i8042_dmi_laptop_table[] = {
+       {
+               .ident = "Portable",
+               .matches = {
+                       DMI_MATCH(DMI_CHASSIS_TYPE, "8"), /* Portable */
+               },
+       },
+       {
+               .ident = "Laptop",
+               .matches = {
+                       DMI_MATCH(DMI_CHASSIS_TYPE, "9"), /* Laptop */
+               },
+       },
+       {
+               .ident = "Notebook",
+               .matches = {
+                       DMI_MATCH(DMI_CHASSIS_TYPE, "10"), /* Notebook */
+               },
+       },
+       {
+               .ident = "Sub-Notebook",
+               .matches = {
+                       DMI_MATCH(DMI_CHASSIS_TYPE, "14"), /* Sub-Notebook */
+               },
+       },
+       { }
+};
 #endif
 
 /*
@@ -530,9 +558,9 @@ static struct dmi_system_id __initdata i8042_dmi_dritek_table[] = {
 #ifdef CONFIG_PNP
 #include <linux/pnp.h>
 
-static int i8042_pnp_kbd_registered;
+static bool i8042_pnp_kbd_registered;
 static unsigned int i8042_pnp_kbd_devices;
-static int i8042_pnp_aux_registered;
+static bool i8042_pnp_aux_registered;
 static unsigned int i8042_pnp_aux_devices;
 
 static int i8042_pnp_command_reg;
@@ -620,12 +648,12 @@ static struct pnp_driver i8042_pnp_aux_driver = {
 static void i8042_pnp_exit(void)
 {
        if (i8042_pnp_kbd_registered) {
-               i8042_pnp_kbd_registered = 0;
+               i8042_pnp_kbd_registered = false;
                pnp_unregister_driver(&i8042_pnp_kbd_driver);
        }
 
        if (i8042_pnp_aux_registered) {
-               i8042_pnp_aux_registered = 0;
+               i8042_pnp_aux_registered = false;
                pnp_unregister_driver(&i8042_pnp_aux_driver);
        }
 }
@@ -633,12 +661,12 @@ static void i8042_pnp_exit(void)
 static int __init i8042_pnp_init(void)
 {
        char kbd_irq_str[4] = { 0 }, aux_irq_str[4] = { 0 };
-       int pnp_data_busted = 0;
+       int pnp_data_busted = false;
        int err;
 
 #ifdef CONFIG_X86
        if (dmi_check_system(i8042_dmi_nopnp_table))
-               i8042_nopnp = 1;
+               i8042_nopnp = true;
 #endif
 
        if (i8042_nopnp) {
@@ -648,11 +676,11 @@ static int __init i8042_pnp_init(void)
 
        err = pnp_register_driver(&i8042_pnp_kbd_driver);
        if (!err)
-               i8042_pnp_kbd_registered = 1;
+               i8042_pnp_kbd_registered = true;
 
        err = pnp_register_driver(&i8042_pnp_aux_driver);
        if (!err)
-               i8042_pnp_aux_registered = 1;
+               i8042_pnp_aux_registered = true;
 
        if (!i8042_pnp_kbd_devices && !i8042_pnp_aux_devices) {
                i8042_pnp_exit();
@@ -680,9 +708,9 @@ static int __init i8042_pnp_init(void)
 
 #if defined(__ia64__)
        if (!i8042_pnp_kbd_devices)
-               i8042_nokbd = 1;
+               i8042_nokbd = true;
        if (!i8042_pnp_aux_devices)
-               i8042_noaux = 1;
+               i8042_noaux = true;
 #endif
 
        if (((i8042_pnp_data_reg & ~0xf) == (i8042_data_reg & ~0xf) &&
@@ -693,7 +721,7 @@ static int __init i8042_pnp_init(void)
                        "using default %#x\n",
                        i8042_pnp_data_reg, i8042_data_reg);
                i8042_pnp_data_reg = i8042_data_reg;
-               pnp_data_busted = 1;
+               pnp_data_busted = true;
        }
 
        if (((i8042_pnp_command_reg & ~0xf) == (i8042_command_reg & ~0xf) &&
@@ -704,7 +732,7 @@ static int __init i8042_pnp_init(void)
                        "using default %#x\n",
                        i8042_pnp_command_reg, i8042_command_reg);
                i8042_pnp_command_reg = i8042_command_reg;
-               pnp_data_busted = 1;
+               pnp_data_busted = true;
        }
 
        if (!i8042_nokbd && !i8042_pnp_kbd_irq) {
@@ -712,7 +740,7 @@ static int __init i8042_pnp_init(void)
                        "PNP: PS/2 controller doesn't have KBD irq; "
                        "using default %d\n", i8042_kbd_irq);
                i8042_pnp_kbd_irq = i8042_kbd_irq;
-               pnp_data_busted = 1;
+               pnp_data_busted = true;
        }
 
        if (!i8042_noaux && !i8042_pnp_aux_irq) {
@@ -721,7 +749,7 @@ static int __init i8042_pnp_init(void)
                                "PNP: PS/2 appears to have AUX port disabled, "
                                "if this is incorrect please boot with "
                                "i8042.nopnp\n");
-                       i8042_noaux = 1;
+                       i8042_noaux = true;
                } else {
                        printk(KERN_WARNING
                                "PNP: PS/2 controller doesn't have AUX irq; "
@@ -735,6 +763,11 @@ static int __init i8042_pnp_init(void)
        i8042_kbd_irq = i8042_pnp_kbd_irq;
        i8042_aux_irq = i8042_pnp_aux_irq;
 
+#ifdef CONFIG_X86
+       i8042_bypass_aux_irq_test = !pnp_data_busted &&
+                                   dmi_check_system(i8042_dmi_laptop_table);
+#endif
+
        return 0;
 }
 
@@ -763,21 +796,21 @@ static int __init i8042_platform_init(void)
                return retval;
 
 #if defined(__ia64__)
-        i8042_reset = 1;
+        i8042_reset = true;
 #endif
 
 #ifdef CONFIG_X86
        if (dmi_check_system(i8042_dmi_reset_table))
-               i8042_reset = 1;
+               i8042_reset = true;
 
        if (dmi_check_system(i8042_dmi_noloop_table))
-               i8042_noloop = 1;
+               i8042_noloop = true;
 
        if (dmi_check_system(i8042_dmi_nomux_table))
-               i8042_nomux = 1;
+               i8042_nomux = true;
 
        if (dmi_check_system(i8042_dmi_dritek_table))
-               i8042_dritek = 1;
+               i8042_dritek = true;
 #endif /* CONFIG_X86 */
 
        return retval;
index 582245c497ebfe1e6ff5b8fbe513a31e483de35f..eb3ff94af58c4cd6e87a41600c9a06cf886011a8 100644 (file)
@@ -28,35 +28,35 @@ MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
 MODULE_DESCRIPTION("i8042 keyboard and mouse controller driver");
 MODULE_LICENSE("GPL");
 
-static unsigned int i8042_nokbd;
+static bool i8042_nokbd;
 module_param_named(nokbd, i8042_nokbd, bool, 0);
 MODULE_PARM_DESC(nokbd, "Do not probe or use KBD port.");
 
-static unsigned int i8042_noaux;
+static bool i8042_noaux;
 module_param_named(noaux, i8042_noaux, bool, 0);
 MODULE_PARM_DESC(noaux, "Do not probe or use AUX (mouse) port.");
 
-static unsigned int i8042_nomux;
+static bool i8042_nomux;
 module_param_named(nomux, i8042_nomux, bool, 0);
 MODULE_PARM_DESC(nomux, "Do not check whether an active multiplexing conrtoller is present.");
 
-static unsigned int i8042_unlock;
+static bool i8042_unlock;
 module_param_named(unlock, i8042_unlock, bool, 0);
 MODULE_PARM_DESC(unlock, "Ignore keyboard lock.");
 
-static unsigned int i8042_reset;
+static bool i8042_reset;
 module_param_named(reset, i8042_reset, bool, 0);
 MODULE_PARM_DESC(reset, "Reset controller during init and cleanup.");