]> git.proxmox.com Git - mirror_ubuntu-kernels.git/commitdiff
Merge commit 'v2.6.31-rc8' into next
authorDmitry Torokhov <dmitry.torokhov@gmail.com>
Fri, 28 Aug 2009 05:00:20 +0000 (22:00 -0700)
committerDmitry Torokhov <dmitry.torokhov@gmail.com>
Fri, 28 Aug 2009 05:00:20 +0000 (22:00 -0700)
52 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/joystick/xpad.c
drivers/input/keyboard/Kconfig
drivers/input/keyboard/Makefile
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/pxa27x_keypad.c
drivers/input/keyboard/sh_keysc.c
drivers/input/keyboard/sunkbd.c
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/hgpk.c
drivers/input/mouse/hil_ptr.c [deleted file]
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/vsxxxaa.c
drivers/input/serio/at32psif.c
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/wm97xx-core.c
drivers/pci/pci-driver.c
include/linux/device.h
include/linux/input/eeti_ts.h [new file with mode: 0644]
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..63e8965ad85d0a3e7c7fd232580d303c9919108a 100644 (file)
@@ -2,6 +2,7 @@
 #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)
@@ -51,8 +52,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 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..50e407de8a78c3468c234d4a43e305e0dcd134bd 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
@@ -361,4 +362,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..152303029203d55fba1b66ba864882bb8c3f0818 100644 (file)
@@ -31,3 +31,4 @@ obj-$(CONFIG_KEYBOARD_STOWAWAY)               += stowaway.o
 obj-$(CONFIG_KEYBOARD_SUNKBD)          += sunkbd.o
 obj-$(CONFIG_KEYBOARD_TOSA)            += tosakbd.o
 obj-$(CONFIG_KEYBOARD_XTKBD)           += xtkbd.o
+obj-$(CONFIG_KEYBOARD_W90P910)         += w90p910_keypad.o
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 0d2fc64a5e1cead895be0a0c22cd96a500faf1c0..c987cc75674cc4ce3f065cd8f154ab9f659316af 100644 (file)
@@ -25,6 +25,7 @@
 #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>
@@ -107,7 +108,7 @@ struct pxa27x_keypad {
        int irq;
 
        /* matrix key code map */
-       unsigned int matrix_keycodes[MAX_MATRIX_KEY_NUM];
+       unsigned short matrix_keycodes[MAX_MATRIX_KEY_NUM];
 
        /* state row bits of each column scan */
        uint32_t matrix_key_state[MAX_MATRIX_KEY_COLS];
@@ -124,21 +125,21 @@ 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;
        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 short code = KEY_VAL(key);
 
                keypad->matrix_keycodes[(row << 3) + col] = code;
-               set_bit(code, input_dev->keybit);
+               __set_bit(code, input_dev->keybit);
        }
+       __clear_bit(KEY_RESERVED, input_dev->keybit);
 
        for (i = 0; i < pdata->direct_key_num; i++)
-               set_bit(pdata->direct_key_map[i], input_dev->keybit);
+               __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;
@@ -149,18 +150,18 @@ static void pxa27x_keypad_build_keycode(struct pxa27x_keypad *keypad)
 
        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);
+                       __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);
+                       __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);
+                       __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);
+                       __set_bit(pdata->rotary1_rel_code, input_dev->relbit);
        }
 }
 
@@ -388,8 +389,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 +402,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,12 +423,12 @@ 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)
 {
@@ -461,14 +464,14 @@ static int __devinit pxa27x_keypad_probe(struct platform_device *pdev)
                goto failed_free;
        }
 
-       res = request_mem_region(res->start, res_size(res), pdev->name);
+       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;
@@ -540,7 +543,7 @@ failed_put_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:
        kfree(keypad);
        return error;
@@ -552,8 +555,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,7 +563,7 @@ 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);
@@ -575,11 +576,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..e7aa935a294a7693f8b9fcaf059b0343eefbd9b4 100644 (file)
@@ -150,8 +150,8 @@ static int sunkbd_event(struct input_dev *dev, unsigned int type, unsigned int c
 
                case EV_LED:
 
-                       sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_SETLED);
-                       sunkbd->serio->write(sunkbd->serio,
+                       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;
@@ -161,11 +161,11 @@ static int sunkbd_event(struct input_dev *dev, unsigned int type, unsigned int c
                        switch (code) {
 
                                case SND_CLICK:
-                                       sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_NOCLICK - value);
+                                       serio_write(sunkbd->serio, SUNKBD_CMD_NOCLICK - value);
                                        return 0;
 
                                case SND_BELL:
-                                       sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_BELLOFF - value);
+                                       serio_write(sunkbd->serio, SUNKBD_CMD_BELLOFF - value);
                                        return 0;
                        }
 
@@ -183,7 +183,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,7 +192,7 @@ 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);
+               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;
@@ -212,12 +212,14 @@ 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)
diff --git a/drivers/input/keyboard/w90p910_keypad.c b/drivers/input/keyboard/w90p910_keypad.c
new file mode 100644 (file)
index 0000000..b8598ae
--- /dev/null
@@ -0,0 +1,291 @@
+/*
+ * 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 = pdata->keymap_data;
+       struct w90p910_keypad *keypad;
+       struct input_dev *input_dev;
+       struct resource *res;
+       int irq;
+       int error;
+       int i;
+
+       if (!pdata) {
+               dev_err(&pdev->dev, "no platform data defined\n");
+               return -EINVAL;
+       }
+
+       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);
+
+       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 keycode = KEY_VAL(key);
+               unsigned int scancode = MATRIX_SCAN_CODE(row, col,
+                                                        W90P910_ROW_SHIFT);
+
+               keypad->keymap[scancode] = keycode;
+               __set_bit(keycode, input_dev->keybit);
+       }
+       __clear_bit(KEY_RESERVED, 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..ebb08cfe27319fc8088bfdfcda0a6624e8ba6413 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;
 }
@@ -1009,8 +1009,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 +1053,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 +1078,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 +1312,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 +1323,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 +1353,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 +1362,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 +1375,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 a1ad2f1a7bb377c776368d55c2a05b5fcd7fd69b..f5aa035774d9e1747d59e6cf6be12e37af62d0f6 100644 (file)
@@ -369,12 +369,46 @@ 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);
 
+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, 0);
+
 static void hgpk_disconnect(struct psmouse *psmouse)
 {
        struct hgpk_data *priv = psmouse->private;
 
        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)
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 b407b355dcebb6ff8e67617047d8878d742d1ef5..df318887ca09b16cdd9379beb99dbb95fe9be5bb 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"
 
@@ -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;
@@ -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",
index 54ed267894bdfaf466a3fc6732bd2252636218b3..cca1744c2a08e8c614dd89752ffb6283b10731be 100644 (file)
@@ -91,6 +91,7 @@ enum psmouse_type {
        PSMOUSE_CORTRON,
        PSMOUSE_HGPK,
        PSMOUSE_ELANTECH,
+       PSMOUSE_FSP,
        PSMOUSE_AUTO            /* This one should always be last */
 };
 
@@ -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, 1)
+
+#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, 1)
+
+#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, 1)
 
 #endif /* _PSMOUSE_H */
diff --git a/drivers/input/mouse/sentelic.c b/drivers/input/mouse/sentelic.c
new file mode 100644 (file)
index 0000000..97b1e72
--- /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, int 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..083559c
--- /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, int set_properties);
+extern int fsp_init(struct psmouse *psmouse);
+#else
+inline int fsp_detect(struct psmouse *psmouse, int set_properties)
+{
+       return -ENOSYS;
+}
+inline int fsp_init(struct psmouse *psmouse)
+{
+       return -ENOSYS;
+}
+#endif
+
+#endif /* __KERNEL__ */
+
+#endif /* !__SENTELIC_H */
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 582245c497ebfe1e6ff5b8fbe513a31e483de35f..9f5c0506242f2e53ac6f18ec00d1b467bf853014 100644 (file)
@@ -923,41 +923,27 @@ static void i8042_dritek_enable(void)
 
 #ifdef CONFIG_PM
 
-static bool i8042_suspended;
-
 /*
- * Here we try to restore the original BIOS settings. We only want to
- * do that once, when we really suspend, not when we taking memory
- * snapshot for swsusp (in this case we'll perform required cleanup
- * as part of shutdown process).
+ * Here we try to restore the original BIOS settings to avoid
+ * upsetting it.
  */
 
-static int i8042_suspend(struct platform_device *dev, pm_message_t state)
+static int i8042_pm_reset(struct device *dev)
 {
-       if (!i8042_suspended && state.event == PM_EVENT_SUSPEND)
-               i8042_controller_reset();
-
-       i8042_suspended = state.event == PM_EVENT_SUSPEND ||
-                         state.event == PM_EVENT_FREEZE;
+       i8042_controller_reset();
 
        return 0;
 }
 
-
 /*
- * Here we try to reset everything back to a state in which suspended
+ * Here we try to reset everything back to a state we had
+ * before suspending.
  */
 
-static int i8042_resume(struct platform_device *dev)
+static int i8042_pm_restore(struct device *dev)
 {
        int error;
 
-/*
- * Do not bother with restoring state if we haven't suspened yet
- */
-       if (!i8042_suspended)
-               return 0;
-
        error = i8042_controller_check();
        if (error)
                return error;
@@ -1001,11 +987,18 @@ static int i8042_resume(struct platform_device *dev)
        if (i8042_ports[I8042_KBD_PORT_NO].serio)
                i8042_enable_kbd_port();
 
-       i8042_suspended = false;
        i8042_interrupt(0, NULL);
 
        return 0;
 }
+
+static const struct dev_pm_ops i8042_pm_ops = {
+       .suspend        = i8042_pm_reset,
+       .resume         = i8042_pm_restore,
+       .poweroff       = i8042_pm_reset,
+       .restore        = i8042_pm_restore,
+};
+
 #endif /* CONFIG_PM */
 
 /*
@@ -1251,14 +1244,13 @@ static struct platform_driver i8042_driver = {
        .driver         = {
                .name   = "i8042",
                .owner  = THIS_MODULE,
+#ifdef CONFIG_PM
+               .pm     = &i8042_pm_ops,
+#endif
        },
        .probe          = i8042_probe,
        .remove         = __devexit_p(i8042_remove),
        .shutdown       = i8042_shutdown,
-#ifdef CONFIG_PM
-       .suspend        = i8042_suspend,
-       .resume         = i8042_resume,
-#endif
 };
 
 static int __init i8042_init(void)
index be5bbbb8ae4ee5105439fc074af9a779654920eb..3a95b508bf27b93b014503f06687a7e9ff92b86b 100644 (file)
@@ -161,7 +161,7 @@ static int ps2_adjust_timeout(struct ps2dev *ps2dev, int command, int timeout)
  * ps2_command() can only be called from a process context
  */
 
-int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command)
+int __ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command)
 {
        int timeout;
        int send = (command >> 12) & 0xf;
@@ -179,8 +179,6 @@ int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command)
                return -1;
        }
 
-       mutex_lock(&ps2dev->cmd_mutex);
-
        serio_pause_rx(ps2dev->serio);
        ps2dev->flags = command == PS2_CMD_GETID ? PS2_FLAG_WAITID : 0;
        ps2dev->cmdcnt = receive;
@@ -231,7 +229,18 @@ int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command)
        ps2dev->flags = 0;
        serio_continue_rx(ps2dev->serio);
 
+       return rc;
+}
+EXPORT_SYMBOL(__ps2_command);
+
+int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command)
+{
+       int rc;
+
+       mutex_lock(&ps2dev->cmd_mutex);
+       rc = __ps2_command(ps2dev, param, command);
        mutex_unlock(&ps2dev->cmd_mutex);
+
        return rc;
 }
 EXPORT_SYMBOL(ps2_command);
index d66f4944f2a0efc0a18508d9c4707bf069567830..0236f0d5fd9156319f01abf3dd4f7d7cf6d2972f 100644 (file)
@@ -931,15 +931,11 @@ static int serio_uevent(struct device *dev, struct kobj_uevent_env *env)
 #endif /* CONFIG_HOTPLUG */
 
 #ifdef CONFIG_PM
-static int serio_suspend(struct device *dev, pm_message_t state)
+static int serio_suspend(struct device *dev)
 {
        struct serio *serio = to_serio_port(dev);
 
-       if (!serio->suspended && state.event == PM_EVENT_SUSPEND)
-               serio_cleanup(serio);
-
-       serio->suspended = state.event == PM_EVENT_SUSPEND ||
-                          state.event == PM_EVENT_FREEZE;
+       serio_cleanup(serio);
 
        return 0;
 }
@@ -952,13 +948,17 @@ static int serio_resume(struct device *dev)
         * Driver reconnect can take a while, so better let kseriod
         * deal with it.
         */
-       if (serio->suspended) {
-               serio->suspended = false;
-               serio_queue_event(serio, NULL, SERIO_RECONNECT_PORT);
-       }
+       serio_queue_event(serio, NULL, SERIO_RECONNECT_PORT);
 
        return 0;
 }
+
+static const struct dev_pm_ops serio_pm_ops = {
+       .suspend        = serio_suspend,
+       .resume         = serio_resume,
+       .poweroff       = serio_suspend,
+       .restore        = serio_resume,
+};
 #endif /* CONFIG_PM */
 
 /* called from serio_driver->connect/disconnect methods under serio_mutex */
@@ -1015,8 +1015,7 @@ static struct bus_type serio_bus = {
        .remove         = serio_driver_remove,
        .shutdown       = serio_shutdown,
 #ifdef CONFIG_PM
-       .suspend        = serio_suspend,
-       .resume         = serio_resume,
+       .pm             = &serio_pm_ops,
 #endif
 };
 
index 72e2712c7e2a6a51ff023d8485d32eb1c941fd1c..87a1ae63bcc4221317dc9d7355cab481eff2e13c 100644 (file)
@@ -366,11 +366,11 @@ config TOUCHSCREEN_WM97XX_ATMEL
          be called atmel-wm97xx.
 
 config TOUCHSCREEN_WM97XX_MAINSTONE
-       tristate "WM97xx Mainstone accelerated touch"
+       tristate "WM97xx Mainstone/Palm accelerated touch"
        depends on TOUCHSCREEN_WM97XX && ARCH_PXA
        help
          Say Y here for support for streaming mode with WM97xx touchscreens
-         on Mainstone systems.
+         on Mainstone, Palm Tungsten T5, TX and LifeDrive systems.
 
          If unsure, say N.
 
@@ -406,6 +406,7 @@ config TOUCHSCREEN_USB_COMPOSITE
          - IRTOUCHSYSTEMS/UNITOP
          - IdealTEK URTC1000
          - GoTop Super_Q2/GogoPen/PenPower tablets
+         - JASTEC USB Touch Controller/DigiTech DTR-02U
 
          Have a look at <http://linux.chapter7.ch/touchkit/> for
          a usage description and the required user-space stuff.
@@ -468,6 +469,16 @@ config TOUCHSCREEN_USB_GOTOP
        bool "GoTop Super_Q2/GogoPen/PenPower tablet device support" if EMBEDDED
        depends on TOUCHSCREEN_USB_COMPOSITE
 
+config TOUCHSCREEN_USB_JASTEC
+       default y
+       bool "JASTEC/DigiTech DTR-02U USB touch controller device support" if EMBEDDED
+       depends on TOUCHSCREEN_USB_COMPOSITE
+
+config TOUCHSCREEN_USB_E2I
+       default y
+       bool "e2i Touchscreen controller (e.g. from Mimo 740)"
+       depends on TOUCHSCREEN_USB_COMPOSITE
+
 config TOUCHSCREEN_TOUCHIT213
        tristate "Sahara TouchIT-213 touchscreen"
        select SERIO
@@ -492,6 +503,7 @@ config TOUCHSCREEN_TSC2007
 
 config TOUCHSCREEN_W90X900
        tristate "W90P910 touchscreen driver"
+       depends on HAVE_CLK
        help
          Say Y here if you have a W90P910 based touchscreen.
 
index 055969e8be132de9a3954c85384b9801b4bcb667..9c7fce4d74d09b3f6ec1927e87ad659a6fc8a910 100644 (file)
@@ -204,14 +204,14 @@ static int __devinit atmel_tsadcc_probe(struct platform_device *pdev)
                goto err_free_dev;
        }
 
-       if (!request_mem_region(res->start, res->end - res->start + 1,
+       if (!request_mem_region(res->start, resource_size(res),
                                "atmel tsadcc regs")) {
                dev_err(&pdev->dev, "resources is unavailable.\n");
                err = -EBUSY;
                goto err_free_dev;
        }
 
-       tsc_base = ioremap(res->start, res->end - res->start + 1);
+       tsc_base = ioremap(res->start, resource_size(res));
        if (!tsc_base) {
                dev_err(&pdev->dev, "failed to map registers.\n");
                err = -ENOMEM;
@@ -286,7 +286,7 @@ err_free_irq:
 err_unmap_regs:
        iounmap(tsc_base);
 err_release_mem:
-       release_mem_region(res->start, res->end - res->start + 1);
+       release_mem_region(res->start, resource_size(res));
 err_free_dev:
        input_free_device(ts_dev->input);
 err_free_mem:
@@ -305,7 +305,7 @@ static int __devexit atmel_tsadcc_remove(struct platform_device *pdev)
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        iounmap(tsc_base);
-       release_mem_region(res->start, res->end - res->start + 1);
+       release_mem_region(res->start, resource_size(res));
 
        clk_disable(ts_dev->clk);
        clk_put(ts_dev->clk);
index 3ab92222a52552fa8463270198ff0b1f6d640c62..9029bd3f34e5ee9b5c12e3ef41c04c09001a45b1 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/i2c.h>
 #include <linux/timer.h>
 #include <linux/gpio.h>
+#include <linux/input/eeti_ts.h>
 
 static int flip_x;
 module_param(flip_x, bool, 0644);
@@ -46,7 +47,7 @@ struct eeti_ts_priv {
        struct input_dev *input;
        struct work_struct work;
        struct mutex mutex;
-       int irq;
+       int irq, irq_active_high;
 };
 
 #define EETI_TS_BITDEPTH       (11)
@@ -58,6 +59,11 @@ struct eeti_ts_priv {
 #define REPORT_BIT_HAS_PRESSURE        (1 << 6)
 #define REPORT_RES_BITS(v)     (((v) >> 1) + EETI_TS_BITDEPTH)
 
+static inline int eeti_ts_irq_active(struct eeti_ts_priv *priv)
+{
+       return gpio_get_value(irq_to_gpio(priv->irq)) == priv->irq_active_high;
+}
+
 static void eeti_ts_read(struct work_struct *work)
 {
        char buf[6];
@@ -67,7 +73,7 @@ static void eeti_ts_read(struct work_struct *work)
 
        mutex_lock(&priv->mutex);
 
-       while (!gpio_get_value(irq_to_gpio(priv->irq)) && --to)
+       while (eeti_ts_irq_active(priv) && --to)
                i2c_master_recv(priv->client, buf, sizeof(buf));
 
        if (!to) {
@@ -140,8 +146,10 @@ static void eeti_ts_close(struct input_dev *dev)
 static int __devinit eeti_ts_probe(struct i2c_client *client,
                                   const struct i2c_device_id *idp)
 {
+       struct eeti_ts_platform_data *pdata;
        struct eeti_ts_priv *priv;
        struct input_dev *input;
+       unsigned int irq_flags;
        int err = -ENOMEM;
 
        /* In contrast to what's described in the datasheet, there seems
@@ -180,6 +188,14 @@ static int __devinit eeti_ts_probe(struct i2c_client *client,
        priv->input = input;
        priv->irq = client->irq;
 
+       pdata = client->dev.platform_data;
+
+       if (pdata)
+               priv->irq_active_high = pdata->irq_active_high;
+
+       irq_flags = priv->irq_active_high ?
+               IRQF_TRIGGER_RISING : IRQF_TRIGGER_FALLING;
+
        INIT_WORK(&priv->work, eeti_ts_read);
        i2c_set_clientdata(client, priv);
        input_set_drvdata(input, priv);
@@ -188,7 +204,7 @@ static int __devinit eeti_ts_probe(struct i2c_client *client,
        if (err)
                goto err1;
 
-       err = request_irq(priv->irq, eeti_ts_isr, IRQF_TRIGGER_FALLING,
+       err = request_irq(priv->irq, eeti_ts_isr, irq_flags,
                          client->name, priv);
        if (err) {
                dev_err(&client->dev, "Unable to request touchscreen IRQ.\n");
index 4d3139e2099d02b6f7bed9432b723fc4b84490e2..b4d7f63deff106a6d08c0507c7e3febe0662e783 100644 (file)
@@ -148,9 +148,10 @@ unsigned int h3600_flite_power(struct input_dev *dev, enum flite_pwr pwr)
        struct h3600_dev *ts = input_get_drvdata(dev);
 
        /* Must be in this order */
-       ts->serio->write(ts->serio, 1);
-       ts->serio->write(ts->serio, pwr);
-       ts->serio->write(ts->serio, brightness);
+       serio_write(ts->serio, 1);
+       serio_write(ts->serio, pwr);
+       serio_write(ts->serio, brightness);
+
        return 0;
 }
 
@@ -262,7 +263,7 @@ static int h3600ts_event(struct input_dev *dev, unsigned int type,
 
        switch (type) {
                case EV_LED: {
-               //      ts->serio->write(ts->serio, SOME_CMD);
+               //      serio_write(ts->serio, SOME_CMD);
                        return 0;
                }
        }
index 4cc047a5116ec0ce61af2a34aefd645fd91404d3..8fc3b08deb3beb9f75651b698a6a7c3b3269cc46 100644 (file)
 #include <linux/interrupt.h>
 #include <linux/wm97xx.h>
 #include <linux/io.h>
+#include <linux/gpio.h>
+
 #include <mach/regs-ac97.h>
 
-#define VERSION                "0.13"
+#include <asm/mach-types.h>
 
 struct continuous {
        u16 id;    /* codec id */
@@ -62,6 +64,7 @@ static const struct continuous cinfo[] = {
 /* continuous speed index */
 static int sp_idx;
 static u16 last, tries;
+static int irq;
 
 /*
  * Pen sampling frequency (Hz) in continuous mode.
@@ -171,7 +174,7 @@ up:
 
 static int wm97xx_acc_startup(struct wm97xx *wm)
 {
-       int idx = 0;
+       int idx = 0, ret = 0;
 
        /* check we have a codec */
        if (wm->ac97 == NULL)
@@ -191,18 +194,40 @@ static int wm97xx_acc_startup(struct wm97xx *wm)
                 "mainstone accelerated touchscreen driver, %d samples/sec\n",
                 cinfo[sp_idx].speed);
 
+       /* IRQ driven touchscreen is used on Palm hardware */
+       if (machine_is_palmt5() || machine_is_palmtx() || machine_is_palmld()) {
+               pen_int = 1;
+               irq = 27;
+               /* There is some obscure mutant of WM9712 interbred with WM9713
+                * used on Palm HW */
+               wm->variant = WM97xx_WM1613;
+       } else if (machine_is_mainstone() && pen_int)
+               irq = 4;
+
+       if (irq) {
+               ret = gpio_request(irq, "Touchscreen IRQ");
+               if (ret)
+                       goto out;
+
+               ret = gpio_direction_input(irq);
+               if (ret) {
+                       gpio_free(irq);
+                       goto out;
+               }
+
+               wm->pen_irq = gpio_to_irq(irq);
+               set_irq_type(wm->pen_irq, IRQ_TYPE_EDGE_BOTH);
+       } else /* pen irq not supported */
+               pen_int = 0;
+
        /* codec specific irq config */
        if (pen_int) {
                switch (wm->id) {
                case WM9705_ID2:
-                       wm->pen_irq = IRQ_GPIO(4);
-                       set_irq_type(IRQ_GPIO(4), IRQ_TYPE_EDGE_BOTH);
                        break;
                case WM9712_ID2:
                case WM9713_ID2:
-                       /* enable pen down interrupt */
                        /* use PEN_DOWN GPIO 13 to assert IRQ on GPIO line 2 */
-                       wm->pen_irq = MAINSTONE_AC97_IRQ;
                        wm97xx_config_gpio(wm, WM97XX_GPIO_13, WM97XX_GPIO_IN,
                                           WM97XX_GPIO_POL_HIGH,
                                           WM97XX_GPIO_STICKY,
@@ -220,23 +245,17 @@ static int wm97xx_acc_startup(struct wm97xx *wm)
                }
        }
 
-       return 0;
+out:
+       return ret;
 }
 
 static void wm97xx_acc_shutdown(struct wm97xx *wm)
 {
        /* codec specific deconfig */
        if (pen_int) {
-               switch (wm->id & 0xffff) {
-               case WM9705_ID2:
-                       wm->pen_irq = 0;
-                       break;
-               case WM9712_ID2:
-               case WM9713_ID2:
-                       /* disable interrupt */
-                       wm->pen_irq = 0;
-                       break;
-               }
+               if (irq)
+                       gpio_free(irq);
+               wm->pen_irq = 0;
        }
 }
 
index 880f58c6a7c44782daab84bd9536316d97d87a39..7ef0d1420d3c917f48d4dd41013d4d4a6f7665f5 100644 (file)
  */
 
 #include <linux/module.h>
-#include <linux/hrtimer.h>
 #include <linux/slab.h>
 #include <linux/input.h>
 #include <linux/interrupt.h>
 #include <linux/i2c.h>
 #include <linux/i2c/tsc2007.h>
 
-#define TS_POLL_DELAY  (10 * 1000)     /* ns delay before the first sample */
-#define TS_POLL_PERIOD (5 * 1000)      /* ns delay between samples */
+#define TS_POLL_DELAY                  1 /* ms delay between samples */
+#define TS_POLL_PERIOD                 1 /* ms delay between samples */
 
 #define TSC2007_MEASURE_TEMP0          (0x0 << 4)
 #define TSC2007_MEASURE_AUX            (0x2 << 4)
@@ -70,17 +69,14 @@ struct ts_event {
 struct tsc2007 {
        struct input_dev        *input;
        char                    phys[32];
-       struct hrtimer          timer;
-       struct ts_event         tc;
+       struct delayed_work     work;
 
        struct i2c_client       *client;
 
-       spinlock_t              lock;
-
        u16                     model;
        u16                     x_plate_ohms;
 
-       unsigned                pendown;
+       bool                    pendown;
        int                     irq;
 
        int                     (*get_pendown_state)(void);
@@ -109,52 +105,96 @@ static inline int tsc2007_xfer(struct tsc2007 *tsc, u8 cmd)
        return val;
 }
 
-static void tsc2007_send_event(void *tsc)
+static void tsc2007_read_values(struct tsc2007 *tsc, struct ts_event *tc)
 {
-       struct tsc2007  *ts = tsc;
-       u32             rt;
-       u16             x, y, z1, z2;
+       /* y- still on; turn on only y+ (and ADC) */
+       tc->y = tsc2007_xfer(tsc, READ_Y);
+
+       /* turn y- off, x+ on, then leave in lowpower */
+       tc->x = tsc2007_xfer(tsc, READ_X);
+
+       /* turn y+ off, x- on; we'll use formula #1 */
+       tc->z1 = tsc2007_xfer(tsc, READ_Z1);
+       tc->z2 = tsc2007_xfer(tsc, READ_Z2);
 
-       x = ts->tc.x;
-       y = ts->tc.y;
-       z1 = ts->tc.z1;
-       z2 = ts->tc.z2;
+       /* Prepare for next touch reading - power down ADC, enable PENIRQ */
+       tsc2007_xfer(tsc, PWRDOWN);
+}
+
+static u32 tsc2007_calculate_pressure(struct tsc2007 *tsc, struct ts_event *tc)
+{
+       u32 rt = 0;
 
        /* range filtering */
-       if (x == MAX_12BIT)
-               x = 0;
+       if (tc->x == MAX_12BIT)
+               tc->x = 0;
 
-       if (likely(x && z1)) {
+       if (likely(tc->x && tc->z1)) {
                /* compute touch pressure resistance using equation #1 */
-               rt = z2;
-               rt -= z1;
-               rt *= x;
-               rt *= ts->x_plate_ohms;
-               rt /= z1;
+               rt = tc->z2 - tc->z1;
+               rt *= tc->x;
+               rt *= tsc->x_plate_ohms;
+               rt /= tc->z1;
                rt = (rt + 2047) >> 12;
-       } else
-               rt = 0;
+       }
+
+       return rt;
+}
+
+static void tsc2007_send_up_event(struct tsc2007 *tsc)
+{
+       struct input_dev *input = tsc->input;
 
-       /* Sample found inconsistent by debouncing or pressure is beyond
-        * the maximum. Don't report it to user space, repeat at least
-        * once more the measurement
+       dev_dbg(&tsc->client->dev, "UP\n");
+
+       input_report_key(input, BTN_TOUCH, 0);
+       input_report_abs(input, ABS_PRESSURE, 0);
+       input_sync(input);
+}
+
+static void tsc2007_work(struct work_struct *work)
+{
+       struct tsc2007 *ts =
+               container_of(to_delayed_work(work), struct tsc2007, work);
+       struct ts_event tc;
+       u32 rt;
+
+       /*
+        * NOTE: We can't rely on the pressure to determine the pen down
+        * state, even though this controller has a pressure sensor.
+        * The pressure value can fluctuate for quite a while after
+        * lifting the pen and in some cases may not even settle at the
+        * expected value.
+        *
+        * The only safe way to check for the pen up condition is in the
+        * work function by reading the pen signal state (it's a GPIO
+        * and IRQ). Unfortunately such callback is not always available,
+        * in that case we have rely on the pressure anyway.
         */
+       if (ts->get_pendown_state) {
+               if (unlikely(!ts->get_pendown_state())) {
+                       tsc2007_send_up_event(ts);
+                       ts->pendown = false;
+                       goto out;
+               }
+
+               dev_dbg(&ts->client->dev, "pen is still down\n");
+       }
+
+       tsc2007_read_values(ts, &tc);
+
+       rt = tsc2007_calculate_pressure(ts, &tc);
        if (rt > MAX_12BIT) {
+               /*
+                * Sample found inconsistent by debouncing or pressure is
+                * beyond the maximum. Don't report it to user space,
+                * repeat at least once more the measurement.
+                */
                dev_dbg(&ts->client->dev, "ignored pressure %d\n", rt);
+               goto out;
 
-               hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_PERIOD),
-                             HRTIMER_MODE_REL);
-               return;
        }
 
-       /* NOTE: We can't rely on the pressure to determine the pen down
-        * state, even this controller has a pressure sensor.  The pressure
-        * value can fluctuate for quite a while after lifting the pen and
-        * in some cases may not even settle at the expected value.
-        *
-        * The only safe way to check for the pen up condition is in the
-        * timer by reading the pen signal state (it's a GPIO _and_ IRQ).
-        */
        if (rt) {
                struct input_dev *input = ts->input;
 
@@ -162,102 +202,74 @@ static void tsc2007_send_event(void *tsc)
                        dev_dbg(&ts->client->dev, "DOWN\n");
 
                        input_report_key(input, BTN_TOUCH, 1);
-                       ts->pendown = 1;
+                       ts->pendown = true;
                }
 
-               input_report_abs(input, ABS_X, x);
-               input_report_abs(input, ABS_Y, y);
+               input_report_abs(input, ABS_X, tc.x);
+               input_report_abs(input, ABS_Y, tc.y);
                input_report_abs(input, ABS_PRESSURE, rt);
 
                input_sync(input);
 
                dev_dbg(&ts->client->dev, "point(%4d,%4d), pressure (%4u)\n",
-                       x, y, rt);
+                       tc.x, tc.y, rt);
+
+       } else if (!ts->get_pendown_state && ts->pendown) {
+               /*
+                * We don't have callback to check pendown state, so we
+                * have to assume that since pressure reported is 0 the
+                * pen was lifted up.
+                */
+               tsc2007_send_up_event(ts);
+               ts->pendown = false;
        }
 
-       hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_PERIOD),
-                       HRTIMER_MODE_REL);
-}
-
-static int tsc2007_read_values(struct tsc2007 *tsc)
-{
-       /* y- still on; turn on only y+ (and ADC) */
-       tsc->tc.y = tsc2007_xfer(tsc, READ_Y);
-
-       /* turn y- off, x+ on, then leave in lowpower */
-       tsc->tc.x = tsc2007_xfer(tsc, READ_X);
-
-       /* turn y+ off, x- on; we'll use formula #1 */
-       tsc->tc.z1 = tsc2007_xfer(tsc, READ_Z1);
-       tsc->tc.z2 = tsc2007_xfer(tsc, READ_Z2);
-
-       /* power down */
-       tsc2007_xfer(tsc, PWRDOWN);
-
-       return 0;
-}
-
-static enum hrtimer_restart tsc2007_timer(struct hrtimer *handle)
-{
-       struct tsc2007 *ts = container_of(handle, struct tsc2007, timer);
-       unsigned long flags;
-
-       spin_lock_irqsave(&ts->lock, flags);
-
-       if (unlikely(!ts->get_pendown_state() && ts->pendown)) {
-               struct input_dev *input = ts->input;
-
-               dev_dbg(&ts->client->dev, "UP\n");
-
-               input_report_key(input, BTN_TOUCH, 0);
-               input_report_abs(input, ABS_PRESSURE, 0);
-               input_sync(input);
-
-               ts->pendown = 0;
+ out:
+       if (ts->pendown)
+               schedule_delayed_work(&ts->work,
+                                     msecs_to_jiffies(TS_POLL_PERIOD));
+       else
                enable_irq(ts->irq);
-       } else {
-               /* pen is still down, continue with the measurement */
-               dev_dbg(&ts->client->dev, "pen is still down\n");
-
-               tsc2007_read_values(ts);
-               tsc2007_send_event(ts);
-       }
-
-       spin_unlock_irqrestore(&ts->lock, flags);
-
-       return HRTIMER_NORESTART;
 }
 
 static irqreturn_t tsc2007_irq(int irq, void *handle)
 {
        struct tsc2007 *ts = handle;
-       unsigned long flags;
-
-       spin_lock_irqsave(&ts->lock, flags);
 
-       if (likely(ts->get_pendown_state())) {
+       if (!ts->get_pendown_state || likely(ts->get_pendown_state())) {
                disable_irq_nosync(ts->irq);
-               hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_DELAY),
-                                       HRTIMER_MODE_REL);
+               schedule_delayed_work(&ts->work,
+                                     msecs_to_jiffies(TS_POLL_DELAY));
        }
 
        if (ts->clear_penirq)
                ts->clear_penirq();
 
-       spin_unlock_irqrestore(&ts->lock, flags);
-
        return IRQ_HANDLED;
 }
 
-static int tsc2007_probe(struct i2c_client *client,
-                       const struct i2c_device_id *id)
+static void tsc2007_free_irq(struct tsc2007 *ts)
+{
+       free_irq(ts->irq, ts);
+       if (cancel_delayed_work_sync(&ts->work)) {
+               /*
+                * Work was pending, therefore we need to enable
+                * IRQ here to balance the disable_irq() done in the
+                * interrupt handler.
+                */
+               enable_irq(ts->irq);
+       }
+}
+
+static int __devinit tsc2007_probe(struct i2c_client *client,
+                                  const struct i2c_device_id *id)
 {
        struct tsc2007 *ts;
        struct tsc2007_platform_data *pdata = pdata = client->dev.platform_data;
        struct input_dev *input_dev;
        int err;
 
-       if (!pdata || !pdata->get_pendown_state) {
+       if (!pdata) {
                dev_err(&client->dev, "platform data is required!\n");
                return -EINVAL;
        }
@@ -274,22 +286,15 @@ static int tsc2007_probe(struct i2c_client *client,
        }
 
        ts->client = client;
-       i2c_set_clientdata(client, ts);
-
+       ts->irq = client->irq;
        ts->input = input_dev;
-
-       hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
-       ts->timer.function = tsc2007_timer;
-
-       spin_lock_init(&ts->lock);
+       INIT_DELAYED_WORK(&ts->work, tsc2007_work);
 
        ts->model             = pdata->model;
        ts->x_plate_ohms      = pdata->x_plate_ohms;
        ts->get_pendown_state = pdata->get_pendown_state;
        ts->clear_penirq      = pdata->clear_penirq;
 
-       pdata->init_platform_hw();
-
        snprintf(ts->phys, sizeof(ts->phys),
                 "%s/input0", dev_name(&client->dev));
 
@@ -304,9 +309,8 @@ static int tsc2007_probe(struct i2c_client *client,
        input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, 0, 0);
        input_set_abs_params(input_dev, ABS_PRESSURE, 0, MAX_12BIT, 0, 0);
 
-       tsc2007_read_values(ts);
-
-       ts->irq = client->irq;
+       if (pdata->init_platform_hw)
+               pdata->init_platform_hw();
 
        err = request_irq(ts->irq, tsc2007_irq, 0,
                        client->dev.driver->name, ts);
@@ -315,33 +319,39 @@ static int tsc2007_probe(struct i2c_client *client,
                goto err_free_mem;
        }
 
+       /* Prepare for touch readings - power down ADC and enable PENIRQ */
+       err = tsc2007_xfer(ts, PWRDOWN);
+       if (err < 0)
+               goto err_free_irq;
+
        err = input_register_device(input_dev);
        if (err)
                goto err_free_irq;
 
-       dev_info(&client->dev, "registered with irq (%d)\n", ts->irq);
+       i2c_set_clientdata(client, ts);
 
        return 0;
 
  err_free_irq:
-       free_irq(ts->irq, ts);
-       hrtimer_cancel(&ts->timer);
+       tsc2007_free_irq(ts);
+       if (pdata->exit_platform_hw)
+               pdata->exit_platform_hw();
  err_free_mem:
        input_free_device(input_dev);
        kfree(ts);
        return err;
 }
 
-static int tsc2007_remove(struct i2c_client *client)
+static int __devexit tsc2007_remove(struct i2c_client *client)
 {
        struct tsc2007  *ts = i2c_get_clientdata(client);
-       struct tsc2007_platform_data *pdata;
+       struct tsc2007_platform_data *pdata = client->dev.platform_data;
 
-       pdata = client->dev.platform_data;
-       pdata->exit_platform_hw();
+       tsc2007_free_irq(ts);
+
+       if (pdata->exit_platform_hw)
+               pdata->exit_platform_hw();
 
-       free_irq(ts->irq, ts);
-       hrtimer_cancel(&ts->timer);
        input_unregister_device(ts->input);
        kfree(ts);
 
@@ -362,7 +372,7 @@ static struct i2c_driver tsc2007_driver = {
        },
        .id_table       = tsc2007_idtable,
        .probe          = tsc2007_probe,
-       .remove         = tsc2007_remove,
+       .remove         = __devexit_p(tsc2007_remove),
 };
 
 static int __init tsc2007_init(void)
index 3a7a58222f836ed5c9aea5022a1196482c7ee355..095f84b1f56e33769a4513a9d635aa3b0100f7f3 100644 (file)
@@ -128,9 +128,10 @@ static inline unsigned int ucb1400_ts_read_yres(struct ucb1400_ts *ucb)
        return ucb1400_adc_read(ucb->ac97, 0, adcsync);
 }
 
-static inline int ucb1400_ts_pen_down(struct snd_ac97 *ac97)
+static inline int ucb1400_ts_pen_up(struct snd_ac97 *ac97)
 {
        unsigned short val = ucb1400_reg_read(ac97, UCB_TS_CR);
+
        return val & (UCB_TS_CR_TSPX_LOW | UCB_TS_CR_TSMX_LOW);
 }
 
@@ -209,7 +210,7 @@ static int ucb1400_ts_thread(void *_ucb)
 
                msleep(10);
 
-               if (ucb1400_ts_pen_down(ucb->ac97)) {
+               if (ucb1400_ts_pen_up(ucb->ac97)) {
                        ucb1400_ts_irq_enable(ucb->ac97);
 
                        /*
index fb7cb9bdfbd5c4971cedeb064b8839ae3d09365a..68ece5801a58c63d5b0f9b183af8948582756210 100644 (file)
@@ -13,6 +13,7 @@
  *  - IdealTEK URTC1000
  *  - General Touch
  *  - GoTop Super_Q2/GogoPen/PenPower tablets
+ *  - JASTEC USB touch controller/DigiTech DTR-02U
  *
  * Copyright (C) 2004-2007 by Daniel Ritz <daniel.ritz@gmx.ch>
  * Copyright (C) by Todd E. Johnson (mtouchusb.c)
@@ -118,6 +119,8 @@ enum {
        DEVTYPE_IDEALTEK,
        DEVTYPE_GENERAL_TOUCH,
        DEVTYPE_GOTOP,
+       DEVTYPE_JASTEC,
+       DEVTYPE_E2I,
 };
 
 #define USB_DEVICE_HID_CLASS(vend, prod) \
@@ -191,10 +194,50 @@ static struct usb_device_id usbtouch_devices[] = {
        {USB_DEVICE(0x08f2, 0x00f4), .driver_info = DEVTYPE_GOTOP},
 #endif
 
+#ifdef CONFIG_TOUCHSCREEN_USB_JASTEC
+       {USB_DEVICE(0x0f92, 0x0001), .driver_info = DEVTYPE_JASTEC},
+#endif
+
+#ifdef CONFIG_TOUCHSCREEN_USB_E2I
+       {USB_DEVICE(0x1ac7, 0x0001), .driver_info = DEVTYPE_E2I},
+#endif
        {}
 };
 
 
+/*****************************************************************************
+ * e2i Part
+ */
+
+#ifdef CONFIG_TOUCHSCREEN_USB_E2I
+static int e2i_init(struct usbtouch_usb *usbtouch)
+{
+       int ret;
+
+       ret = usb_control_msg(usbtouch->udev, usb_rcvctrlpipe(usbtouch->udev, 0),
+                             0x01, 0x02, 0x0000, 0x0081,
+                             NULL, 0, USB_CTRL_SET_TIMEOUT);
+
+       dbg("%s - usb_control_msg - E2I_RESET - bytes|err: %d",
+           __func__, ret);
+       return ret;
+}
+
+static int e2i_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
+{
+       int tmp = (pkt[0] << 8) | pkt[1];
+       dev->x  = (pkt[2] << 8) | pkt[3];
+       dev->y  = (pkt[4] << 8) | pkt[5];
+
+       tmp = tmp - 0xA000;
+       dev->touch = (tmp > 0);
+       dev->press = (tmp > 0 ? tmp : 0);
+
+       return 1;
+}
+#endif
+
+
 /*****************************************************************************
  * eGalax part
  */
@@ -559,6 +602,21 @@ static int gotop_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
        dev->x = ((pkt[1] & 0x38) << 4) | pkt[2];
        dev->y = ((pkt[1] & 0x07) << 7) | pkt[3];
        dev->touch = pkt[0] & 0x01;
+
+       return 1;
+}
+#endif
+
+/*****************************************************************************
+ * JASTEC Part
+ */
+#ifdef CONFIG_TOUCHSCREEN_USB_JASTEC
+static int jastec_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
+{
+       dev->x = ((pkt[0] & 0x3f) << 6) | (pkt[2] & 0x3f);
+       dev->y = ((pkt[1] & 0x3f) << 6) | (pkt[3] & 0x3f);
+       dev->touch = (pkt[0] & 0x40) >> 6;
+
        return 1;
 }
 #endif
@@ -702,6 +760,29 @@ static struct usbtouch_device_info usbtouch_dev_info[] = {
                .read_data      = gotop_read_data,
        },
 #endif
+
+#ifdef CONFIG_TOUCHSCREEN_USB_JASTEC
+       [DEVTYPE_JASTEC] = {
+               .min_xc         = 0x0,
+               .max_xc         = 0x0fff,
+               .min_yc         = 0x0,
+               .max_yc         = 0x0fff,
+               .rept_size      = 4,
+               .read_data      = jastec_read_data,
+       },
+#endif
+
+#ifdef CONFIG_TOUCHSCREEN_USB_E2I
+       [DEVTYPE_E2I] = {
+               .min_xc         = 0x0,
+               .max_xc         = 0x7fff,
+               .min_yc         = 0x0,
+               .max_yc         = 0x7fff,
+               .rept_size      = 6,
+               .init           = e2i_init,
+               .read_data      = e2i_read_data,
+       },
+#endif
 };
 
 
index 6071f5882572e2659ec77eae1a7f4d62554cd2fc..dc4c9d6b67c782f4fafe9725980a48fbf57a1555 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/io.h>
+#include <linux/clk.h>
 #include <linux/input.h>
 #include <linux/interrupt.h>
 
@@ -47,8 +48,8 @@ enum ts_state {
 struct w90p910_ts {
        struct input_dev *input;
        struct timer_list timer;
+       struct clk *clk;
        int irq_num;
-       void __iomem *clocken;
        void __iomem *ts_reg;
        spinlock_t lock;
        enum ts_state state;
@@ -166,8 +167,7 @@ static int w90p910_open(struct input_dev *dev)
        unsigned long val;
 
        /* enable the ADC clock */
-       val = __raw_readl(w90p910_ts->clocken);
-       __raw_writel(val | ADC_CLK_EN, w90p910_ts->clocken);
+       clk_enable(w90p910_ts->clk);
 
        __raw_writel(ADC_RST1, w90p910_ts->ts_reg);
        msleep(1);
@@ -211,8 +211,7 @@ static void w90p910_close(struct input_dev *dev)
        del_timer_sync(&w90p910_ts->timer);
 
        /* stop the ADC clock */
-       val = __raw_readl(w90p910_ts->clocken);
-       __raw_writel(val & ~ADC_CLK_EN, w90p910_ts->clocken);
+       clk_disable(w90p910_ts->clk);
 }
 
 static int __devinit w90x900ts_probe(struct platform_device *pdev)
@@ -241,26 +240,24 @@ static int __devinit w90x900ts_probe(struct platform_device *pdev)
                goto fail1;
        }
 
-       if (!request_mem_region(res->start, res->end - res->start + 1,
+       if (!request_mem_region(res->start, resource_size(res),
                                pdev->name)) {
                err = -EBUSY;
                goto fail1;
        }
 
-       w90p910_ts->ts_reg = ioremap(res->start, res->end - res->start + 1);
+       w90p910_ts->ts_reg = ioremap(res->start, resource_size(res));
        if (!w90p910_ts->ts_reg) {
                err = -ENOMEM;
                goto fail2;
        }
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-       if (!res) {
-               err = -ENXIO;
+       w90p910_ts->clk = clk_get(&pdev->dev, NULL);
+       if (IS_ERR(w90p910_ts->clk)) {
+               err = PTR_ERR(w90p910_ts->clk);
                goto fail3;
        }
 
-       w90p910_ts->clocken = (void __iomem *)res->start;
-
        input_dev->name = "W90P910 TouchScreen";
        input_dev->phys = "w90p910ts/event0";
        input_dev->id.bustype = BUS_HOST;
@@ -283,20 +280,21 @@ static int __devinit w90x900ts_probe(struct platform_device *pdev)
        if (request_irq(w90p910_ts->irq_num, w90p910_ts_interrupt,
                        IRQF_DISABLED, "w90p910ts", w90p910_ts)) {
                err = -EBUSY;
-               goto fail3;
+               goto fail4;
        }
 
        err = input_register_device(w90p910_ts->input);
        if (err)
-               goto fail4;
+               goto fail5;
 
        platform_set_drvdata(pdev, w90p910_ts);
 
        return 0;
 
-fail4: free_irq(w90p910_ts->irq_num, w90p910_ts);
+fail5: free_irq(w90p910_ts->irq_num, w90p910_ts);
+fail4: clk_put(w90p910_ts->clk);
 fail3: iounmap(w90p910_ts->ts_reg);
-fail2: release_mem_region(res->start, res->end - res->start + 1);
+fail2: release_mem_region(res->start, resource_size(res));
 fail1: input_free_device(input_dev);
        kfree(w90p910_ts);
        return err;
@@ -311,8 +309,10 @@ static int __devexit w90x900ts_remove(struct platform_device *pdev)
        del_timer_sync(&w90p910_ts->timer);
        iounmap(w90p910_ts->ts_reg);
 
+       clk_put(w90p910_ts->clk);
+
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       release_mem_region(res->start, res->end - res->start + 1);
+       release_mem_region(res->start, resource_size(res));
 
        input_unregister_device(w90p910_ts->input);
        kfree(w90p910_ts);
index 2957d48e0045fa05d68bb38aafe6ec8c9d3462d8..252eb11fe9db141118aef9b086c5590eb588d063 100644 (file)
@@ -204,7 +204,7 @@ void wm97xx_set_gpio(struct wm97xx *wm, u32 gpio,
        else
                reg &= ~gpio;
 
-       if (wm->id == WM9712_ID2)
+       if (wm->id == WM9712_ID2 && wm->variant != WM97xx_WM1613)
                wm97xx_reg_write(wm, AC97_GPIO_STATUS, reg << 1);
        else
                wm97xx_reg_write(wm, AC97_GPIO_STATUS, reg);
@@ -307,7 +307,7 @@ static void wm97xx_pen_irq_worker(struct work_struct *work)
                                         WM97XX_GPIO_13);
                }
 
-               if (wm->id == WM9712_ID2)
+               if (wm->id == WM9712_ID2 && wm->variant != WM97xx_WM1613)
                        wm97xx_reg_write(wm, AC97_GPIO_STATUS, (status &
                                                ~WM97XX_GPIO_13) << 1);
                else
@@ -582,6 +582,8 @@ static int wm97xx_probe(struct device *dev)
 
        wm->id = wm97xx_reg_read(wm, AC97_VENDOR_ID2);
 
+       wm->variant = WM97xx_GENERIC;
+
        dev_info(wm->dev, "detected a wm97%02x codec\n", wm->id & 0xff);
 
        switch (wm->id & 0xff) {
index f99bc7f089f1ab8c0839775c58f2cabc487e37cf..a7eb7277b106020e1dbbea143a97bba5f95a6c47 100644 (file)
@@ -575,7 +575,7 @@ static void pci_pm_complete(struct device *dev)
 static int pci_pm_suspend(struct device *dev)
 {
        struct pci_dev *pci_dev = to_pci_dev(dev);
-       struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
+       const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
 
        if (pci_has_legacy_pm_support(pci_dev))
                return pci_legacy_suspend(dev, PMSG_SUSPEND);
@@ -613,7 +613,7 @@ static int pci_pm_suspend(struct device *dev)
 static int pci_pm_suspend_noirq(struct device *dev)
 {
        struct pci_dev *pci_dev = to_pci_dev(dev);
-       struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
+       const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
 
        if (pci_has_legacy_pm_support(pci_dev))
                return pci_legacy_suspend_late(dev, PMSG_SUSPEND);
@@ -672,7 +672,7 @@ static int pci_pm_resume_noirq(struct device *dev)
 static int pci_pm_resume(struct device *dev)
 {
        struct pci_dev *pci_dev = to_pci_dev(dev);
-       struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
+       const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
        int error = 0;
 
        /*
@@ -711,7 +711,7 @@ static int pci_pm_resume(struct device *dev)
 static int pci_pm_freeze(struct device *dev)
 {
        struct pci_dev *pci_dev = to_pci_dev(dev);
-       struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
+       const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
 
        if (pci_has_legacy_pm_support(pci_dev))
                return pci_legacy_suspend(dev, PMSG_FREEZE);
@@ -780,7 +780,7 @@ static int pci_pm_thaw_noirq(struct device *dev)
 static int pci_pm_thaw(struct device *dev)
 {
        struct pci_dev *pci_dev = to_pci_dev(dev);
-       struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
+       const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
        int error = 0;
 
        if (pci_has_legacy_pm_support(pci_dev))
@@ -799,7 +799,7 @@ static int pci_pm_thaw(struct device *dev)
 static int pci_pm_poweroff(struct device *dev)
 {
        struct pci_dev *pci_dev = to_pci_dev(dev);
-       struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
+       const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
 
        if (pci_has_legacy_pm_support(pci_dev))
                return pci_legacy_suspend(dev, PMSG_HIBERNATE);
@@ -872,7 +872,7 @@ static int pci_pm_restore_noirq(struct device *dev)
 static int pci_pm_restore(struct device *dev)
 {
        struct pci_dev *pci_dev = to_pci_dev(dev);
-       struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
+       const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
        int error = 0;
 
        /*
@@ -910,7 +910,7 @@ static int pci_pm_restore(struct device *dev)
 
 #endif /* !CONFIG_HIBERNATION */
 
-struct dev_pm_ops pci_dev_pm_ops = {
+const struct dev_pm_ops pci_dev_pm_ops = {
        .prepare = pci_pm_prepare,
        .complete = pci_pm_complete,
        .suspend = pci_pm_suspend,
index aebb81036db2d368a7b55664f5a2b9d102c5109d..a28642975053f9cf63480f11325463da410947c9 100644 (file)
@@ -62,7 +62,7 @@ struct bus_type {
        int (*suspend)(struct device *dev, pm_message_t state);
        int (*resume)(struct device *dev);
 
-       struct dev_pm_ops *pm;
+       const struct dev_pm_ops *pm;
 
        struct bus_type_private *p;
 };
@@ -132,7 +132,7 @@ struct device_driver {
        int (*resume) (struct device *dev);
        struct attribute_group **groups;
 
-       struct dev_pm_ops *pm;
+       const struct dev_pm_ops *pm;
 
        struct driver_private *p;
 };
@@ -200,7 +200,8 @@ struct class {
        int (*suspend)(struct device *dev, pm_message_t state);
        int (*resume)(struct device *dev);
 
-       struct dev_pm_ops *pm;
+       const struct dev_pm_ops *pm;
+
        struct class_private *p;
 };
 
@@ -291,7 +292,7 @@ struct device_type {
        char *(*nodename)(struct device *dev);
        void (*release)(struct device *dev);
 
-       struct dev_pm_ops *pm;
+       const struct dev_pm_ops *pm;
 };
 
 /* interface for exporting device attributes */
diff --git a/include/linux/input/eeti_ts.h b/include/linux/input/eeti_ts.h
new file mode 100644 (file)
index 0000000..f875b31
--- /dev/null
@@ -0,0 +1,9 @@
+#ifndef LINUX_INPUT_EETI_TS_H
+#define LINUX_INPUT_EETI_TS_H
+
+struct eeti_ts_platform_data {
+       unsigned int irq_active_high;
+};
+
+#endif /* LINUX_INPUT_EETI_TS_H */
+
index b94534b7e26658b805978e153339378c847575e8..fcf5fbe6a50c3596be52388d74e210d6b4c38231 100644 (file)
@@ -44,6 +44,7 @@ struct ps2dev {
 void ps2_init(struct ps2dev *ps2dev, struct serio *serio);
 int ps2_sendbyte(struct ps2dev *ps2dev, unsigned char byte, int timeout);
 void ps2_drain(struct ps2dev *ps2dev, int maxbytes, int timeout);
+int __ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command);
 int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command);
 int ps2_handle_ack(struct ps2dev *ps2dev, unsigned char data);
 int ps2_handle_response(struct ps2dev *ps2dev, unsigned char data);
index 126d24c9eaa86a8fa374f9a28285e51e0ef7a4a5..a640bc2afe76542493236decb1790b7fc9a06495 100644 (file)
@@ -31,8 +31,6 @@ struct serio {
 
        bool manual_bind;
        bool registered;        /* port has been fully registered with driver core */
-       bool suspended;         /* port is suspended */
-
 
        struct serio_device_id id;
 
index 6f69968eab244f63ec956c2ce7cb8cdb6ca9bacf..0c9878123d5fa7096efd679c81058ed53662ad46 100644 (file)
 #include <linux/input.h>       /* Input device layer */
 #include <linux/platform_device.h>
 
+/*
+ * WM97xx variants
+ */
+#define        WM97xx_GENERIC                  0x0000
+#define        WM97xx_WM1613                   0x1613
+
 /*
  * WM97xx AC97 Touchscreen registers
  */
@@ -283,6 +289,7 @@ struct wm97xx {
        unsigned pen_is_down:1;         /* Pen is down */
        unsigned aux_waiting:1;         /* aux measurement waiting */
        unsigned pen_probably_down:1;   /* used in polling mode */
+       u16 variant;                    /* WM97xx chip variant */
        u16 suspend_mode;               /* PRP in suspend mode */
 };