Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input: (52 commits) Input: bcm5974 - silence uninitialized variables warnings Input: wistron_btns - add keymap for AOpen 1557 Input: psmouse - use boolean type Input: i8042 - use platform_driver_probe Input: i8042 - use boolean type where it makes sense Input: i8042 - try disabling and re-enabling AUX port at close Input: pxa27x_keypad - allow modifying keymap from userspace Input: sunkbd - fix formatting Input: i8042 - bypass AUX IRQ delivery test on laptops Input: wacom_w8001 - simplify querying logic Input: atkbd - allow setting force-release bitmap via sysfs Input: w90p910_keypad - move a dereference below a NULL test Input: add twl4030_keypad driver Input: matrix-keypad - add function to build device keymap Input: tosakbd - fix cleaning up KEY_STROBEs after error Input: joydev - validate axis/button maps before clobbering current ones Input: xpad - add USB ID for the drumkit controller from Rock Band Input: w90p910_keypad - rename driver name to match platform Input: add new driver for Sentelic Finger Sensing Pad Input: psmouse - allow defining read-only attributes ...
This commit is contained in:
commit
133309a89e
77 changed files with 4352 additions and 1577 deletions
475
Documentation/input/sentelic.txt
Normal file
475
Documentation/input/sentelic.txt
Normal file
|
@ -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
|
|
@ -2,9 +2,12 @@
|
|||
#define __ASM_ARCH_PXA27x_KEYPAD_H
|
||||
|
||||
#include <linux/input.h>
|
||||
#include <linux/input/matrix_keypad.h>
|
||||
|
||||
#define MAX_MATRIX_KEY_ROWS (8)
|
||||
#define MAX_MATRIX_KEY_COLS (8)
|
||||
#define MATRIX_ROW_SHIFT (3)
|
||||
#define MAX_DIRECT_KEY_NUM (8)
|
||||
|
||||
/* pxa3xx keypad platform specific parameters
|
||||
*
|
||||
|
@ -33,7 +36,7 @@ struct pxa27x_keypad_platform_data {
|
|||
|
||||
/* direct keys */
|
||||
int direct_key_num;
|
||||
unsigned int direct_key_map[8];
|
||||
unsigned int direct_key_map[MAX_DIRECT_KEY_NUM];
|
||||
|
||||
/* rotary encoders 0 */
|
||||
int enable_rotary0;
|
||||
|
@ -51,8 +54,6 @@ struct pxa27x_keypad_platform_data {
|
|||
unsigned int debounce_interval;
|
||||
};
|
||||
|
||||
#define KEY(row, col, val) (((row) << 28) | ((col) << 24) | (val))
|
||||
|
||||
extern void pxa_set_keypad_info(struct pxa27x_keypad_platform_data *info);
|
||||
|
||||
#endif /* __ASM_ARCH_PXA27x_KEYPAD_H */
|
||||
|
|
15
arch/arm/mach-w90x900/include/mach/w90p910_keypad.h
Normal file
15
arch/arm/mach-w90x900/include/mach/w90p910_keypad.h
Normal file
|
@ -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 */
|
39
arch/blackfin/include/asm/bfin_rotary.h
Normal file
39
arch/blackfin/include/asm/bfin_rotary.h
Normal file
|
@ -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
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -452,6 +452,76 @@ static unsigned int joydev_poll(struct file *file, poll_table *wait)
|
|||
(joydev->exist ? 0 : (POLLHUP | POLLERR));
|
||||
}
|
||||
|
||||
static int joydev_handle_JSIOCSAXMAP(struct joydev *joydev,
|
||||
void __user *argp, size_t len)
|
||||
{
|
||||
__u8 *abspam;
|
||||
int i;
|
||||
int retval = 0;
|
||||
|
||||
len = min(len, sizeof(joydev->abspam));
|
||||
|
||||
/* Validate the map. */
|
||||
abspam = kmalloc(len, GFP_KERNEL);
|
||||
if (!abspam)
|
||||
return -ENOMEM;
|
||||
|
||||
if (copy_from_user(abspam, argp, len)) {
|
||||
retval = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i = 0; i < joydev->nabs; i++) {
|
||||
if (abspam[i] > ABS_MAX) {
|
||||
retval = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(joydev->abspam, abspam, len);
|
||||
|
||||
out:
|
||||
kfree(abspam);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int joydev_handle_JSIOCSBTNMAP(struct joydev *joydev,
|
||||
void __user *argp, size_t len)
|
||||
{
|
||||
__u16 *keypam;
|
||||
int i;
|
||||
int retval = 0;
|
||||
|
||||
len = min(len, sizeof(joydev->keypam));
|
||||
|
||||
/* Validate the map. */
|
||||
keypam = kmalloc(len, GFP_KERNEL);
|
||||
if (!keypam)
|
||||
return -ENOMEM;
|
||||
|
||||
if (copy_from_user(keypam, argp, len)) {
|
||||
retval = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i = 0; i < joydev->nkey; i++) {
|
||||
if (keypam[i] > KEY_MAX || keypam[i] < BTN_MISC) {
|
||||
retval = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(joydev->keypam, keypam, len);
|
||||
|
||||
for (i = 0; i < joydev->nkey; i++)
|
||||
joydev->keymap[keypam[i] - BTN_MISC] = i;
|
||||
|
||||
out:
|
||||
kfree(keypam);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
static int joydev_ioctl_common(struct joydev *joydev,
|
||||
unsigned int cmd, void __user *argp)
|
||||
{
|
||||
|
@ -512,46 +582,18 @@ static int joydev_ioctl_common(struct joydev *joydev,
|
|||
switch (cmd & ~IOCSIZE_MASK) {
|
||||
|
||||
case (JSIOCSAXMAP & ~IOCSIZE_MASK):
|
||||
len = min_t(size_t, _IOC_SIZE(cmd), sizeof(joydev->abspam));
|
||||
/*
|
||||
* FIXME: we should not copy into our axis map before
|
||||
* validating the data.
|
||||
*/
|
||||
if (copy_from_user(joydev->abspam, argp, len))
|
||||
return -EFAULT;
|
||||
|
||||
for (i = 0; i < joydev->nabs; i++) {
|
||||
if (joydev->abspam[i] > ABS_MAX)
|
||||
return -EINVAL;
|
||||
joydev->absmap[joydev->abspam[i]] = i;
|
||||
}
|
||||
return 0;
|
||||
return joydev_handle_JSIOCSAXMAP(joydev, argp, _IOC_SIZE(cmd));
|
||||
|
||||
case (JSIOCGAXMAP & ~IOCSIZE_MASK):
|
||||
len = min_t(size_t, _IOC_SIZE(cmd), sizeof(joydev->abspam));
|
||||
return copy_to_user(argp, joydev->abspam, len) ? -EFAULT : 0;
|
||||
return copy_to_user(argp, joydev->abspam, len) ? -EFAULT : len;
|
||||
|
||||
case (JSIOCSBTNMAP & ~IOCSIZE_MASK):
|
||||
len = min_t(size_t, _IOC_SIZE(cmd), sizeof(joydev->keypam));
|
||||
/*
|
||||
* FIXME: we should not copy into our keymap before
|
||||
* validating the data.
|
||||
*/
|
||||
if (copy_from_user(joydev->keypam, argp, len))
|
||||
return -EFAULT;
|
||||
|
||||
for (i = 0; i < joydev->nkey; i++) {
|
||||
if (joydev->keypam[i] > KEY_MAX ||
|
||||
joydev->keypam[i] < BTN_MISC)
|
||||
return -EINVAL;
|
||||
joydev->keymap[joydev->keypam[i] - BTN_MISC] = i;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return joydev_handle_JSIOCSBTNMAP(joydev, argp, _IOC_SIZE(cmd));
|
||||
|
||||
case (JSIOCGBTNMAP & ~IOCSIZE_MASK):
|
||||
len = min_t(size_t, _IOC_SIZE(cmd), sizeof(joydev->keypam));
|
||||
return copy_to_user(argp, joydev->keypam, len) ? -EFAULT : 0;
|
||||
return copy_to_user(argp, joydev->keypam, len) ? -EFAULT : len;
|
||||
|
||||
case JSIOCGNAME(0):
|
||||
name = dev->name;
|
||||
|
|
|
@ -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 */
|
||||
{ }
|
||||
};
|
||||
|
||||
|
|
|
@ -187,7 +187,7 @@ config KEYBOARD_HIL_OLD
|
|||
submenu.
|
||||
|
||||
config KEYBOARD_HIL
|
||||
tristate "HP HIL keyboard support"
|
||||
tristate "HP HIL keyboard/pointer support"
|
||||
depends on GSC || HP300
|
||||
default y
|
||||
select HP_SDC
|
||||
|
@ -196,7 +196,8 @@ config KEYBOARD_HIL
|
|||
help
|
||||
The "Human Interface Loop" is a older, 8-channel USB-like
|
||||
controller used in several Hewlett Packard models.
|
||||
This driver implements support for HIL-keyboards attached
|
||||
This driver implements support for HIL-keyboards and pointing
|
||||
devices (mice, tablets, touchscreens) attached
|
||||
to your machine, so normally you should say Y here.
|
||||
|
||||
config KEYBOARD_HP6XX
|
||||
|
@ -329,6 +330,17 @@ config KEYBOARD_OMAP
|
|||
To compile this driver as a module, choose M here: the
|
||||
module will be called omap-keypad.
|
||||
|
||||
config KEYBOARD_TWL4030
|
||||
tristate "TI TWL4030/TWL5030/TPS659x0 keypad support"
|
||||
depends on TWL4030_CORE
|
||||
help
|
||||
Say Y here if your board use the keypad controller on
|
||||
TWL4030 family chips. It's safe to say enable this
|
||||
even on boards that don't use the keypad controller.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called twl4030_keypad.
|
||||
|
||||
config KEYBOARD_TOSA
|
||||
tristate "Tosa keyboard"
|
||||
depends on MACH_TOSA
|
||||
|
@ -361,4 +373,14 @@ config KEYBOARD_XTKBD
|
|||
To compile this driver as a module, choose M here: the
|
||||
module will be called xtkbd.
|
||||
|
||||
config KEYBOARD_W90P910
|
||||
tristate "W90P910 Matrix Keypad support"
|
||||
depends on ARCH_W90X900
|
||||
help
|
||||
Say Y here to enable the matrix keypad on evaluation board
|
||||
based on W90P910.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called w90p910_keypad.
|
||||
|
||||
endif
|
||||
|
|
|
@ -30,4 +30,6 @@ obj-$(CONFIG_KEYBOARD_SPITZ) += spitzkbd.o
|
|||
obj-$(CONFIG_KEYBOARD_STOWAWAY) += stowaway.o
|
||||
obj-$(CONFIG_KEYBOARD_SUNKBD) += sunkbd.o
|
||||
obj-$(CONFIG_KEYBOARD_TOSA) += tosakbd.o
|
||||
obj-$(CONFIG_KEYBOARD_TWL4030) += twl4030_keypad.o
|
||||
obj-$(CONFIG_KEYBOARD_XTKBD) += xtkbd.o
|
||||
obj-$(CONFIG_KEYBOARD_W90P910) += w90p910_keypad.o
|
||||
|
|
|
@ -68,7 +68,9 @@ MODULE_PARM_DESC(extra, "Enable extra LEDs and keys on IBM RapidAcces, EzKey and
|
|||
* are loadable via a userland utility.
|
||||
*/
|
||||
|
||||
static const unsigned short atkbd_set2_keycode[512] = {
|
||||
#define ATKBD_KEYMAP_SIZE 512
|
||||
|
||||
static const unsigned short atkbd_set2_keycode[ATKBD_KEYMAP_SIZE] = {
|
||||
|
||||
#ifdef CONFIG_KEYBOARD_ATKBD_HP_KEYCODES
|
||||
|
||||
|
@ -99,7 +101,7 @@ static const unsigned short atkbd_set2_keycode[512] = {
|
|||
#endif
|
||||
};
|
||||
|
||||
static const unsigned short atkbd_set3_keycode[512] = {
|
||||
static const unsigned short atkbd_set3_keycode[ATKBD_KEYMAP_SIZE] = {
|
||||
|
||||
0, 0, 0, 0, 0, 0, 0, 59, 1,138,128,129,130, 15, 41, 60,
|
||||
131, 29, 42, 86, 58, 16, 2, 61,133, 56, 44, 31, 30, 17, 3, 62,
|
||||
|
@ -200,8 +202,8 @@ struct atkbd {
|
|||
char phys[32];
|
||||
|
||||
unsigned short id;
|
||||
unsigned short keycode[512];
|
||||
DECLARE_BITMAP(force_release_mask, 512);
|
||||
unsigned short keycode[ATKBD_KEYMAP_SIZE];
|
||||
DECLARE_BITMAP(force_release_mask, ATKBD_KEYMAP_SIZE);
|
||||
unsigned char set;
|
||||
unsigned char translated;
|
||||
unsigned char extra;
|
||||
|
@ -253,6 +255,7 @@ static struct device_attribute atkbd_attr_##_name = \
|
|||
__ATTR(_name, S_IWUSR | S_IRUGO, atkbd_do_show_##_name, atkbd_do_set_##_name);
|
||||
|
||||
ATKBD_DEFINE_ATTR(extra);
|
||||
ATKBD_DEFINE_ATTR(force_release);
|
||||
ATKBD_DEFINE_ATTR(scroll);
|
||||
ATKBD_DEFINE_ATTR(set);
|
||||
ATKBD_DEFINE_ATTR(softrepeat);
|
||||
|
@ -272,6 +275,7 @@ ATKBD_DEFINE_RO_ATTR(err_count);
|
|||
|
||||
static struct attribute *atkbd_attributes[] = {
|
||||
&atkbd_attr_extra.attr,
|
||||
&atkbd_attr_force_release.attr,
|
||||
&atkbd_attr_scroll.attr,
|
||||
&atkbd_attr_set.attr,
|
||||
&atkbd_attr_softrepeat.attr,
|
||||
|
@ -934,7 +938,7 @@ static void atkbd_set_keycode_table(struct atkbd *atkbd)
|
|||
int i, j;
|
||||
|
||||
memset(atkbd->keycode, 0, sizeof(atkbd->keycode));
|
||||
bitmap_zero(atkbd->force_release_mask, 512);
|
||||
bitmap_zero(atkbd->force_release_mask, ATKBD_KEYMAP_SIZE);
|
||||
|
||||
if (atkbd->translated) {
|
||||
for (i = 0; i < 128; i++) {
|
||||
|
@ -1041,7 +1045,7 @@ static void atkbd_set_device_attrs(struct atkbd *atkbd)
|
|||
input_dev->keycodesize = sizeof(unsigned short);
|
||||
input_dev->keycodemax = ARRAY_SIZE(atkbd_set2_keycode);
|
||||
|
||||
for (i = 0; i < 512; i++)
|
||||
for (i = 0; i < ATKBD_KEYMAP_SIZE; i++)
|
||||
if (atkbd->keycode[i] && atkbd->keycode[i] < ATKBD_SPECIAL)
|
||||
__set_bit(atkbd->keycode[i], input_dev->keybit);
|
||||
}
|
||||
|
@ -1309,6 +1313,33 @@ static ssize_t atkbd_set_extra(struct atkbd *atkbd, const char *buf, size_t coun
|
|||
return count;
|
||||
}
|
||||
|
||||
static ssize_t atkbd_show_force_release(struct atkbd *atkbd, char *buf)
|
||||
{
|
||||
size_t len = bitmap_scnlistprintf(buf, PAGE_SIZE - 2,
|
||||
atkbd->force_release_mask, ATKBD_KEYMAP_SIZE);
|
||||
|
||||
buf[len++] = '\n';
|
||||
buf[len] = '\0';
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static ssize_t atkbd_set_force_release(struct atkbd *atkbd,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
/* 64 bytes on stack should be acceptable */
|
||||
DECLARE_BITMAP(new_mask, ATKBD_KEYMAP_SIZE);
|
||||
int err;
|
||||
|
||||
err = bitmap_parselist(buf, new_mask, ATKBD_KEYMAP_SIZE);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
memcpy(atkbd->force_release_mask, new_mask, sizeof(atkbd->force_release_mask));
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
static ssize_t atkbd_show_scroll(struct atkbd *atkbd, char *buf)
|
||||
{
|
||||
return sprintf(buf, "%d\n", atkbd->scroll ? 1 : 0);
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -37,19 +37,19 @@
|
|||
#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)
|
||||
{
|
||||
if ((p & ~HIL_CMDCT_POL) == (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_POL))
|
||||
return false;
|
||||
|
||||
if ((p & ~HIL_CMDCT_RPL) == (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_RPL))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void hil_dev_handle_command_response(struct hil_dev *dev)
|
||||
{
|
||||
struct input_dev *dev = kbd->dev;
|
||||
hil_packet *data = kbd->data;
|
||||
hil_packet p;
|
||||
int idx, i, cnt;
|
||||
char *buf;
|
||||
int i, idx;
|
||||
|
||||
idx = kbd->idx4/4;
|
||||
p = data[idx - 1];
|
||||
idx = dev->idx4 / 4;
|
||||
p = dev->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++)
|
||||
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 int hil_kbd_connect(struct serio *serio, struct serio_driver *drv)
|
||||
static void hil_dev_keyboard_setup(struct hil_dev *kbd)
|
||||
{
|
||||
struct hil_kbd *kbd;
|
||||
uint8_t did, *idd;
|
||||
int i;
|
||||
struct input_dev *input_dev = kbd->dev;
|
||||
uint8_t did = kbd->idd[0];
|
||||
int i;
|
||||
|
||||
kbd = kzalloc(sizeof(*kbd), GFP_KERNEL);
|
||||
if (!kbd)
|
||||
return -ENOMEM;
|
||||
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);
|
||||
|
||||
kbd->dev = input_allocate_device();
|
||||
if (!kbd->dev)
|
||||
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 void hil_dev_pointer_setup(struct hil_dev *ptr)
|
||||
{
|
||||
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);
|
||||
|
||||
for (i = 0; i < ptr->naxes; i++)
|
||||
__set_bit(REL_X + i, input_dev->relbit);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
dev->serio = serio;
|
||||
dev->dev = input_dev;
|
||||
|
||||
error = serio_open(serio, drv);
|
||||
if (error)
|
||||
goto bail0;
|
||||
|
||||
if (serio_open(serio, drv))
|
||||
goto bail1;
|
||||
|
||||
serio_set_drvdata(serio, kbd);
|
||||
kbd->serio = serio;
|
||||
|
||||
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);
|
||||
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;
|
||||
|
||||
serio->write(serio, 0);
|
||||
serio->write(serio, 0);
|
||||
serio->write(serio, HIL_PKT_CMD >> 8);
|
||||
serio->write(serio, HIL_CMD_RSC);
|
||||
down(&kbd->sem);
|
||||
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;
|
||||
|
||||
serio->write(serio, 0);
|
||||
serio->write(serio, 0);
|
||||
serio->write(serio, HIL_PKT_CMD >> 8);
|
||||
serio->write(serio, HIL_CMD_RNM);
|
||||
down(&kbd->sem);
|
||||
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;
|
||||
|
||||
serio->write(serio, 0);
|
||||
serio->write(serio, 0);
|
||||
serio->write(serio, HIL_PKT_CMD >> 8);
|
||||
serio->write(serio, HIL_CMD_EXD);
|
||||
down(&kbd->sem);
|
||||
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;
|
||||
|
||||
up(&kbd->sem);
|
||||
did = dev->idd[0];
|
||||
idd = dev->idd + 1;
|
||||
|
||||
did = kbd->idd[0];
|
||||
idd = kbd->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]);
|
||||
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;
|
||||
}
|
||||
|
||||
dev->is_pointer = false;
|
||||
hil_dev_keyboard_setup(dev);
|
||||
break;
|
||||
|
||||
case HIL_IDD_DID_TYPE_REL:
|
||||
case HIL_IDD_DID_TYPE_ABS:
|
||||
dev->is_pointer = true;
|
||||
hil_dev_pointer_setup(dev);
|
||||
break;
|
||||
|
||||
default:
|
||||
goto bail2;
|
||||
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;
|
||||
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 */
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
for (i = 0; i < 128; i++) {
|
||||
set_bit(hil_kbd_set1[i], kbd->dev->keybit);
|
||||
set_bit(hil_kbd_set3[i], kbd->dev->keybit);
|
||||
}
|
||||
clear_bit(0, kbd->dev->keybit);
|
||||
|
||||
input_register_device(kbd->dev);
|
||||
printk(KERN_INFO "input: %s, ID: %d\n",
|
||||
kbd->dev->name, did);
|
||||
|
||||
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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -319,7 +319,6 @@ static int __devinit matrix_keypad_probe(struct platform_device *pdev)
|
|||
struct input_dev *input_dev;
|
||||
unsigned short *keycodes;
|
||||
unsigned int row_shift;
|
||||
int i;
|
||||
int err;
|
||||
|
||||
pdata = pdev->dev.platform_data;
|
||||
|
@ -363,18 +362,10 @@ static int __devinit matrix_keypad_probe(struct platform_device *pdev)
|
|||
|
||||
input_dev->keycode = keycodes;
|
||||
input_dev->keycodesize = sizeof(*keycodes);
|
||||
input_dev->keycodemax = pdata->num_row_gpios << keypad->row_shift;
|
||||
input_dev->keycodemax = pdata->num_row_gpios << row_shift;
|
||||
|
||||
for (i = 0; i < keymap_data->keymap_size; i++) {
|
||||
unsigned int key = keymap_data->keymap[i];
|
||||
unsigned int row = KEY_ROW(key);
|
||||
unsigned int col = KEY_COL(key);
|
||||
unsigned short code = KEY_VAL(key);
|
||||
|
||||
keycodes[MATRIX_SCAN_CODE(row, col, row_shift)] = code;
|
||||
__set_bit(code, input_dev->keybit);
|
||||
}
|
||||
__clear_bit(KEY_RESERVED, input_dev->keybit);
|
||||
matrix_keypad_build_keymap(keymap_data, row_shift,
|
||||
input_dev->keycode, input_dev->keybit);
|
||||
|
||||
input_set_capability(input_dev, EV_MSC, MSC_SCAN);
|
||||
input_set_drvdata(input_dev, keypad);
|
||||
|
|
|
@ -25,13 +25,13 @@
|
|||
#include <linux/platform_device.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/input/matrix_keypad.h>
|
||||
|
||||
#include <asm/mach/arch.h>
|
||||
#include <asm/mach/map.h>
|
||||
|
||||
#include <mach/hardware.h>
|
||||
#include <mach/pxa27x_keypad.h>
|
||||
|
||||
/*
|
||||
* Keypad Controller registers
|
||||
*/
|
||||
|
@ -95,7 +95,8 @@
|
|||
#define keypad_readl(off) __raw_readl(keypad->mmio_base + (off))
|
||||
#define keypad_writel(off, v) __raw_writel((v), keypad->mmio_base + (off))
|
||||
|
||||
#define MAX_MATRIX_KEY_NUM (8 * 8)
|
||||
#define MAX_MATRIX_KEY_NUM (MAX_MATRIX_KEY_ROWS * MAX_MATRIX_KEY_COLS)
|
||||
#define MAX_KEYPAD_KEYS (MAX_MATRIX_KEY_NUM + MAX_DIRECT_KEY_NUM)
|
||||
|
||||
struct pxa27x_keypad {
|
||||
struct pxa27x_keypad_platform_data *pdata;
|
||||
|
@ -106,73 +107,82 @@ struct pxa27x_keypad {
|
|||
|
||||
int irq;
|
||||
|
||||
/* matrix key code map */
|
||||
unsigned int matrix_keycodes[MAX_MATRIX_KEY_NUM];
|
||||
unsigned short keycodes[MAX_KEYPAD_KEYS];
|
||||
int rotary_rel_code[2];
|
||||
|
||||
/* state row bits of each column scan */
|
||||
uint32_t matrix_key_state[MAX_MATRIX_KEY_COLS];
|
||||
uint32_t direct_key_state;
|
||||
|
||||
unsigned int direct_key_mask;
|
||||
|
||||
int rotary_rel_code[2];
|
||||
int rotary_up_key[2];
|
||||
int rotary_down_key[2];
|
||||
};
|
||||
|
||||
static void pxa27x_keypad_build_keycode(struct pxa27x_keypad *keypad)
|
||||
{
|
||||
struct pxa27x_keypad_platform_data *pdata = keypad->pdata;
|
||||
struct input_dev *input_dev = keypad->input_dev;
|
||||
unsigned int *key;
|
||||
unsigned short keycode;
|
||||
int i;
|
||||
|
||||
key = &pdata->matrix_key_map[0];
|
||||
for (i = 0; i < pdata->matrix_key_map_size; i++, key++) {
|
||||
int row = ((*key) >> 28) & 0xf;
|
||||
int col = ((*key) >> 24) & 0xf;
|
||||
int code = (*key) & 0xffffff;
|
||||
for (i = 0; i < pdata->matrix_key_map_size; i++) {
|
||||
unsigned int key = pdata->matrix_key_map[i];
|
||||
unsigned int row = KEY_ROW(key);
|
||||
unsigned int col = KEY_COL(key);
|
||||
unsigned int scancode = MATRIX_SCAN_CODE(row, col,
|
||||
MATRIX_ROW_SHIFT);
|
||||
|
||||
keypad->matrix_keycodes[(row << 3) + col] = code;
|
||||
set_bit(code, input_dev->keybit);
|
||||
keycode = KEY_VAL(key);
|
||||
keypad->keycodes[scancode] = keycode;
|
||||
__set_bit(keycode, input_dev->keybit);
|
||||
}
|
||||
|
||||
for (i = 0; i < pdata->direct_key_num; i++)
|
||||
set_bit(pdata->direct_key_map[i], input_dev->keybit);
|
||||
|
||||
keypad->rotary_up_key[0] = pdata->rotary0_up_key;
|
||||
keypad->rotary_up_key[1] = pdata->rotary1_up_key;
|
||||
keypad->rotary_down_key[0] = pdata->rotary0_down_key;
|
||||
keypad->rotary_down_key[1] = pdata->rotary1_down_key;
|
||||
keypad->rotary_rel_code[0] = pdata->rotary0_rel_code;
|
||||
keypad->rotary_rel_code[1] = pdata->rotary1_rel_code;
|
||||
for (i = 0; i < pdata->direct_key_num; i++) {
|
||||
keycode = pdata->direct_key_map[i];
|
||||
keypad->keycodes[MAX_MATRIX_KEY_NUM + i] = keycode;
|
||||
__set_bit(keycode, input_dev->keybit);
|
||||
}
|
||||
|
||||
if (pdata->enable_rotary0) {
|
||||
if (pdata->rotary0_up_key && pdata->rotary0_down_key) {
|
||||
set_bit(pdata->rotary0_up_key, input_dev->keybit);
|
||||
set_bit(pdata->rotary0_down_key, input_dev->keybit);
|
||||
} else
|
||||
set_bit(pdata->rotary0_rel_code, input_dev->relbit);
|
||||
keycode = pdata->rotary0_up_key;
|
||||
keypad->keycodes[MAX_MATRIX_KEY_NUM + 0] = keycode;
|
||||
__set_bit(keycode, input_dev->keybit);
|
||||
|
||||
keycode = pdata->rotary0_down_key;
|
||||
keypad->keycodes[MAX_MATRIX_KEY_NUM + 1] = keycode;
|
||||
__set_bit(keycode, input_dev->keybit);
|
||||
|
||||
keypad->rotary_rel_code[0] = -1;
|
||||
} else {
|
||||
keypad->rotary_rel_code[0] = pdata->rotary0_rel_code;
|
||||
__set_bit(pdata->rotary0_rel_code, input_dev->relbit);
|
||||
}
|
||||
}
|
||||
|
||||
if (pdata->enable_rotary1) {
|
||||
if (pdata->rotary1_up_key && pdata->rotary1_down_key) {
|
||||
set_bit(pdata->rotary1_up_key, input_dev->keybit);
|
||||
set_bit(pdata->rotary1_down_key, input_dev->keybit);
|
||||
} else
|
||||
set_bit(pdata->rotary1_rel_code, input_dev->relbit);
|
||||
}
|
||||
}
|
||||
keycode = pdata->rotary1_up_key;
|
||||
keypad->keycodes[MAX_MATRIX_KEY_NUM + 2] = keycode;
|
||||
__set_bit(keycode, input_dev->keybit);
|
||||
|
||||
static inline unsigned int lookup_matrix_keycode(
|
||||
struct pxa27x_keypad *keypad, int row, int col)
|
||||
{
|
||||
return keypad->matrix_keycodes[(row << 3) + col];
|
||||
keycode = pdata->rotary1_down_key;
|
||||
keypad->keycodes[MAX_MATRIX_KEY_NUM + 3] = keycode;
|
||||
__set_bit(keycode, input_dev->keybit);
|
||||
|
||||
keypad->rotary_rel_code[1] = -1;
|
||||
} else {
|
||||
keypad->rotary_rel_code[1] = pdata->rotary1_rel_code;
|
||||
__set_bit(pdata->rotary1_rel_code, input_dev->relbit);
|
||||
}
|
||||
}
|
||||
|
||||
__clear_bit(KEY_RESERVED, input_dev->keybit);
|
||||
}
|
||||
|
||||
static void pxa27x_keypad_scan_matrix(struct pxa27x_keypad *keypad)
|
||||
{
|
||||
struct pxa27x_keypad_platform_data *pdata = keypad->pdata;
|
||||
struct input_dev *input_dev = keypad->input_dev;
|
||||
int row, col, num_keys_pressed = 0;
|
||||
uint32_t new_state[MAX_MATRIX_KEY_COLS];
|
||||
uint32_t kpas = keypad_readl(KPAS);
|
||||
|
@ -215,6 +225,7 @@ static void pxa27x_keypad_scan_matrix(struct pxa27x_keypad *keypad)
|
|||
scan:
|
||||
for (col = 0; col < pdata->matrix_key_cols; col++) {
|
||||
uint32_t bits_changed;
|
||||
int code;
|
||||
|
||||
bits_changed = keypad->matrix_key_state[col] ^ new_state[col];
|
||||
if (bits_changed == 0)
|
||||
|
@ -224,12 +235,13 @@ static void pxa27x_keypad_scan_matrix(struct pxa27x_keypad *keypad)
|
|||
if ((bits_changed & (1 << row)) == 0)
|
||||
continue;
|
||||
|
||||
input_report_key(keypad->input_dev,
|
||||
lookup_matrix_keycode(keypad, row, col),
|
||||
new_state[col] & (1 << row));
|
||||
code = MATRIX_SCAN_CODE(row, col, MATRIX_ROW_SHIFT);
|
||||
input_event(input_dev, EV_MSC, MSC_SCAN, code);
|
||||
input_report_key(input_dev, keypad->keycodes[code],
|
||||
new_state[col] & (1 << row));
|
||||
}
|
||||
}
|
||||
input_sync(keypad->input_dev);
|
||||
input_sync(input_dev);
|
||||
memcpy(keypad->matrix_key_state, new_state, sizeof(new_state));
|
||||
}
|
||||
|
||||
|
@ -252,13 +264,15 @@ static void report_rotary_event(struct pxa27x_keypad *keypad, int r, int delta)
|
|||
if (delta == 0)
|
||||
return;
|
||||
|
||||
if (keypad->rotary_up_key[r] && keypad->rotary_down_key[r]) {
|
||||
int keycode = (delta > 0) ? keypad->rotary_up_key[r] :
|
||||
keypad->rotary_down_key[r];
|
||||
if (keypad->rotary_rel_code[r] == -1) {
|
||||
int code = MAX_MATRIX_KEY_NUM + 2 * r + (delta > 0 ? 0 : 1);
|
||||
unsigned char keycode = keypad->keycodes[code];
|
||||
|
||||
/* simulate a press-n-release */
|
||||
input_event(dev, EV_MSC, MSC_SCAN, code);
|
||||
input_report_key(dev, keycode, 1);
|
||||
input_sync(dev);
|
||||
input_event(dev, EV_MSC, MSC_SCAN, code);
|
||||
input_report_key(dev, keycode, 0);
|
||||
input_sync(dev);
|
||||
} else {
|
||||
|
@ -286,6 +300,7 @@ static void pxa27x_keypad_scan_rotary(struct pxa27x_keypad *keypad)
|
|||
static void pxa27x_keypad_scan_direct(struct pxa27x_keypad *keypad)
|
||||
{
|
||||
struct pxa27x_keypad_platform_data *pdata = keypad->pdata;
|
||||
struct input_dev *input_dev = keypad->input_dev;
|
||||
unsigned int new_state;
|
||||
uint32_t kpdk, bits_changed;
|
||||
int i;
|
||||
|
@ -295,9 +310,6 @@ static void pxa27x_keypad_scan_direct(struct pxa27x_keypad *keypad)
|
|||
if (pdata->enable_rotary0 || pdata->enable_rotary1)
|
||||
pxa27x_keypad_scan_rotary(keypad);
|
||||
|
||||
if (pdata->direct_key_map == NULL)
|
||||
return;
|
||||
|
||||
new_state = KPDK_DK(kpdk) & keypad->direct_key_mask;
|
||||
bits_changed = keypad->direct_key_state ^ new_state;
|
||||
|
||||
|
@ -305,12 +317,15 @@ static void pxa27x_keypad_scan_direct(struct pxa27x_keypad *keypad)
|
|||
return;
|
||||
|
||||
for (i = 0; i < pdata->direct_key_num; i++) {
|
||||
if (bits_changed & (1 << i))
|
||||
input_report_key(keypad->input_dev,
|
||||
pdata->direct_key_map[i],
|
||||
(new_state & (1 << i)));
|
||||
if (bits_changed & (1 << i)) {
|
||||
int code = MAX_MATRIX_KEY_NUM + i;
|
||||
|
||||
input_event(input_dev, EV_MSC, MSC_SCAN, code);
|
||||
input_report_key(input_dev, keypad->keycodes[code],
|
||||
new_state & (1 << i));
|
||||
}
|
||||
}
|
||||
input_sync(keypad->input_dev);
|
||||
input_sync(input_dev);
|
||||
keypad->direct_key_state = new_state;
|
||||
}
|
||||
|
||||
|
@ -388,8 +403,9 @@ static void pxa27x_keypad_close(struct input_dev *dev)
|
|||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int pxa27x_keypad_suspend(struct platform_device *pdev, pm_message_t state)
|
||||
static int pxa27x_keypad_suspend(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct pxa27x_keypad *keypad = platform_get_drvdata(pdev);
|
||||
|
||||
clk_disable(keypad->clk);
|
||||
|
@ -400,8 +416,9 @@ static int pxa27x_keypad_suspend(struct platform_device *pdev, pm_message_t stat
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int pxa27x_keypad_resume(struct platform_device *pdev)
|
||||
static int pxa27x_keypad_resume(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct pxa27x_keypad *keypad = platform_get_drvdata(pdev);
|
||||
struct input_dev *input_dev = keypad->input_dev;
|
||||
|
||||
|
@ -420,55 +437,58 @@ static int pxa27x_keypad_resume(struct platform_device *pdev)
|
|||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#define pxa27x_keypad_suspend NULL
|
||||
#define pxa27x_keypad_resume NULL
|
||||
#endif
|
||||
|
||||
#define res_size(res) ((res)->end - (res)->start + 1)
|
||||
static const struct dev_pm_ops pxa27x_keypad_pm_ops = {
|
||||
.suspend = pxa27x_keypad_suspend,
|
||||
.resume = pxa27x_keypad_resume,
|
||||
};
|
||||
#endif
|
||||
|
||||
static int __devinit pxa27x_keypad_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct pxa27x_keypad_platform_data *pdata = pdev->dev.platform_data;
|
||||
struct pxa27x_keypad *keypad;
|
||||
struct input_dev *input_dev;
|
||||
struct resource *res;
|
||||
int irq, error;
|
||||
|
||||
keypad = kzalloc(sizeof(struct pxa27x_keypad), GFP_KERNEL);
|
||||
if (keypad == NULL) {
|
||||
dev_err(&pdev->dev, "failed to allocate driver data\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
keypad->pdata = pdev->dev.platform_data;
|
||||
if (keypad->pdata == NULL) {
|
||||
if (pdata == NULL) {
|
||||
dev_err(&pdev->dev, "no platform data defined\n");
|
||||
error = -EINVAL;
|
||||
goto failed_free;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
dev_err(&pdev->dev, "failed to get keypad irq\n");
|
||||
error = -ENXIO;
|
||||
goto failed_free;
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (res == NULL) {
|
||||
dev_err(&pdev->dev, "failed to get I/O memory\n");
|
||||
error = -ENXIO;
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
keypad = kzalloc(sizeof(struct pxa27x_keypad), GFP_KERNEL);
|
||||
input_dev = input_allocate_device();
|
||||
if (!keypad || !input_dev) {
|
||||
dev_err(&pdev->dev, "failed to allocate memory\n");
|
||||
error = -ENOMEM;
|
||||
goto failed_free;
|
||||
}
|
||||
|
||||
res = request_mem_region(res->start, res_size(res), pdev->name);
|
||||
keypad->pdata = pdata;
|
||||
keypad->input_dev = input_dev;
|
||||
keypad->irq = irq;
|
||||
|
||||
res = request_mem_region(res->start, resource_size(res), pdev->name);
|
||||
if (res == NULL) {
|
||||
dev_err(&pdev->dev, "failed to request I/O memory\n");
|
||||
error = -EBUSY;
|
||||
goto failed_free;
|
||||
}
|
||||
|
||||
keypad->mmio_base = ioremap(res->start, res_size(res));
|
||||
keypad->mmio_base = ioremap(res->start, resource_size(res));
|
||||
if (keypad->mmio_base == NULL) {
|
||||
dev_err(&pdev->dev, "failed to remap I/O memory\n");
|
||||
error = -ENXIO;
|
||||
|
@ -482,43 +502,35 @@ static int __devinit pxa27x_keypad_probe(struct platform_device *pdev)
|
|||
goto failed_free_io;
|
||||
}
|
||||
|
||||
/* Create and register the input driver. */
|
||||
input_dev = input_allocate_device();
|
||||
if (!input_dev) {
|
||||
dev_err(&pdev->dev, "failed to allocate input device\n");
|
||||
error = -ENOMEM;
|
||||
goto failed_put_clk;
|
||||
}
|
||||
|
||||
input_dev->name = pdev->name;
|
||||
input_dev->id.bustype = BUS_HOST;
|
||||
input_dev->open = pxa27x_keypad_open;
|
||||
input_dev->close = pxa27x_keypad_close;
|
||||
input_dev->dev.parent = &pdev->dev;
|
||||
|
||||
keypad->input_dev = input_dev;
|
||||
input_dev->keycode = keypad->keycodes;
|
||||
input_dev->keycodesize = sizeof(keypad->keycodes[0]);
|
||||
input_dev->keycodemax = ARRAY_SIZE(keypad->keycodes);
|
||||
|
||||
input_set_drvdata(input_dev, keypad);
|
||||
|
||||
input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
|
||||
if ((keypad->pdata->enable_rotary0 &&
|
||||
keypad->pdata->rotary0_rel_code) ||
|
||||
(keypad->pdata->enable_rotary1 &&
|
||||
keypad->pdata->rotary1_rel_code)) {
|
||||
input_dev->evbit[0] |= BIT_MASK(EV_REL);
|
||||
}
|
||||
input_set_capability(input_dev, EV_MSC, MSC_SCAN);
|
||||
|
||||
pxa27x_keypad_build_keycode(keypad);
|
||||
platform_set_drvdata(pdev, keypad);
|
||||
|
||||
if ((pdata->enable_rotary0 && keypad->rotary_rel_code[0] != -1) ||
|
||||
(pdata->enable_rotary1 && keypad->rotary_rel_code[1] != -1)) {
|
||||
input_dev->evbit[0] |= BIT_MASK(EV_REL);
|
||||
}
|
||||
|
||||
error = request_irq(irq, pxa27x_keypad_irq_handler, IRQF_DISABLED,
|
||||
pdev->name, keypad);
|
||||
if (error) {
|
||||
dev_err(&pdev->dev, "failed to request IRQ\n");
|
||||
goto failed_free_dev;
|
||||
goto failed_put_clk;
|
||||
}
|
||||
|
||||
keypad->irq = irq;
|
||||
|
||||
/* Register the input device */
|
||||
error = input_register_device(input_dev);
|
||||
if (error) {
|
||||
|
@ -526,22 +538,21 @@ static int __devinit pxa27x_keypad_probe(struct platform_device *pdev)
|
|||
goto failed_free_irq;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, keypad);
|
||||
device_init_wakeup(&pdev->dev, 1);
|
||||
|
||||
return 0;
|
||||
|
||||
failed_free_irq:
|
||||
free_irq(irq, pdev);
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
failed_free_dev:
|
||||
input_free_device(input_dev);
|
||||
failed_put_clk:
|
||||
clk_put(keypad->clk);
|
||||
failed_free_io:
|
||||
iounmap(keypad->mmio_base);
|
||||
failed_free_mem:
|
||||
release_mem_region(res->start, res_size(res));
|
||||
release_mem_region(res->start, resource_size(res));
|
||||
failed_free:
|
||||
input_free_device(input_dev);
|
||||
kfree(keypad);
|
||||
return error;
|
||||
}
|
||||
|
@ -552,8 +563,6 @@ static int __devexit pxa27x_keypad_remove(struct platform_device *pdev)
|
|||
struct resource *res;
|
||||
|
||||
free_irq(keypad->irq, pdev);
|
||||
|
||||
clk_disable(keypad->clk);
|
||||
clk_put(keypad->clk);
|
||||
|
||||
input_unregister_device(keypad->input_dev);
|
||||
|
@ -562,10 +571,11 @@ static int __devexit pxa27x_keypad_remove(struct platform_device *pdev)
|
|||
iounmap(keypad->mmio_base);
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
release_mem_region(res->start, res_size(res));
|
||||
release_mem_region(res->start, resource_size(res));
|
||||
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
kfree(keypad);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -575,11 +585,12 @@ MODULE_ALIAS("platform:pxa27x-keypad");
|
|||
static struct platform_driver pxa27x_keypad_driver = {
|
||||
.probe = pxa27x_keypad_probe,
|
||||
.remove = __devexit_p(pxa27x_keypad_remove),
|
||||
.suspend = pxa27x_keypad_suspend,
|
||||
.resume = pxa27x_keypad_resume,
|
||||
.driver = {
|
||||
.name = "pxa27x-keypad",
|
||||
.owner = THIS_MODULE,
|
||||
#ifdef CONFIG_PM
|
||||
.pm = &pxa27x_keypad_pm_ops,
|
||||
#endif
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -73,7 +73,7 @@ static unsigned char sunkbd_keycode[128] = {
|
|||
*/
|
||||
|
||||
struct sunkbd {
|
||||
unsigned char keycode[128];
|
||||
unsigned char keycode[ARRAY_SIZE(sunkbd_keycode)];
|
||||
struct input_dev *dev;
|
||||
struct serio *serio;
|
||||
struct work_struct tq;
|
||||
|
@ -81,7 +81,7 @@ struct sunkbd {
|
|||
char name[64];
|
||||
char phys[32];
|
||||
char type;
|
||||
unsigned char enabled;
|
||||
bool enabled;
|
||||
volatile s8 reset;
|
||||
volatile s8 layout;
|
||||
};
|
||||
|
@ -94,10 +94,14 @@ struct sunkbd {
|
|||
static irqreturn_t sunkbd_interrupt(struct serio *serio,
|
||||
unsigned char data, unsigned int flags)
|
||||
{
|
||||
struct sunkbd* sunkbd = serio_get_drvdata(serio);
|
||||
struct sunkbd *sunkbd = serio_get_drvdata(serio);
|
||||
|
||||
if (sunkbd->reset <= -1) { /* If cp[i] is 0xff, sunkbd->reset will stay -1. */
|
||||
sunkbd->reset = data; /* The keyboard sends 0xff 0xff 0xID on powerup */
|
||||
if (sunkbd->reset <= -1) {
|
||||
/*
|
||||
* If cp[i] is 0xff, sunkbd->reset will stay -1.
|
||||
* The keyboard sends 0xff 0xff 0xID on powerup.
|
||||
*/
|
||||
sunkbd->reset = data;
|
||||
wake_up_interruptible(&sunkbd->wait);
|
||||
goto out;
|
||||
}
|
||||
|
@ -110,29 +114,33 @@ static irqreturn_t sunkbd_interrupt(struct serio *serio,
|
|||
|
||||
switch (data) {
|
||||
|
||||
case SUNKBD_RET_RESET:
|
||||
schedule_work(&sunkbd->tq);
|
||||
sunkbd->reset = -1;
|
||||
case SUNKBD_RET_RESET:
|
||||
schedule_work(&sunkbd->tq);
|
||||
sunkbd->reset = -1;
|
||||
break;
|
||||
|
||||
case SUNKBD_RET_LAYOUT:
|
||||
sunkbd->layout = -1;
|
||||
break;
|
||||
|
||||
case SUNKBD_RET_ALLUP: /* All keys released */
|
||||
break;
|
||||
|
||||
default:
|
||||
if (!sunkbd->enabled)
|
||||
break;
|
||||
|
||||
case SUNKBD_RET_LAYOUT:
|
||||
sunkbd->layout = -1;
|
||||
break;
|
||||
|
||||
case SUNKBD_RET_ALLUP: /* All keys released */
|
||||
break;
|
||||
|
||||
default:
|
||||
if (!sunkbd->enabled)
|
||||
break;
|
||||
|
||||
if (sunkbd->keycode[data & SUNKBD_KEY]) {
|
||||
input_report_key(sunkbd->dev, sunkbd->keycode[data & SUNKBD_KEY], !(data & SUNKBD_RELEASE));
|
||||
input_sync(sunkbd->dev);
|
||||
} else {
|
||||
printk(KERN_WARNING "sunkbd.c: Unknown key (scancode %#x) %s.\n",
|
||||
data & SUNKBD_KEY, data & SUNKBD_RELEASE ? "released" : "pressed");
|
||||
}
|
||||
if (sunkbd->keycode[data & SUNKBD_KEY]) {
|
||||
input_report_key(sunkbd->dev,
|
||||
sunkbd->keycode[data & SUNKBD_KEY],
|
||||
!(data & SUNKBD_RELEASE));
|
||||
input_sync(sunkbd->dev);
|
||||
} else {
|
||||
printk(KERN_WARNING
|
||||
"sunkbd.c: Unknown key (scancode %#x) %s.\n",
|
||||
data & SUNKBD_KEY,
|
||||
data & SUNKBD_RELEASE ? "released" : "pressed");
|
||||
}
|
||||
}
|
||||
out:
|
||||
return IRQ_HANDLED;
|
||||
|
@ -142,34 +150,37 @@ static irqreturn_t sunkbd_interrupt(struct serio *serio,
|
|||
* sunkbd_event() handles events from the input module.
|
||||
*/
|
||||
|
||||
static int sunkbd_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
|
||||
static int sunkbd_event(struct input_dev *dev,
|
||||
unsigned int type, unsigned int code, int value)
|
||||
{
|
||||
struct sunkbd *sunkbd = input_get_drvdata(dev);
|
||||
|
||||
switch (type) {
|
||||
|
||||
case EV_LED:
|
||||
case EV_LED:
|
||||
|
||||
sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_SETLED);
|
||||
sunkbd->serio->write(sunkbd->serio,
|
||||
(!!test_bit(LED_CAPSL, dev->led) << 3) | (!!test_bit(LED_SCROLLL, dev->led) << 2) |
|
||||
(!!test_bit(LED_COMPOSE, dev->led) << 1) | !!test_bit(LED_NUML, dev->led));
|
||||
serio_write(sunkbd->serio, SUNKBD_CMD_SETLED);
|
||||
serio_write(sunkbd->serio,
|
||||
(!!test_bit(LED_CAPSL, dev->led) << 3) |
|
||||
(!!test_bit(LED_SCROLLL, dev->led) << 2) |
|
||||
(!!test_bit(LED_COMPOSE, dev->led) << 1) |
|
||||
!!test_bit(LED_NUML, dev->led));
|
||||
return 0;
|
||||
|
||||
case EV_SND:
|
||||
|
||||
switch (code) {
|
||||
|
||||
case SND_CLICK:
|
||||
serio_write(sunkbd->serio, SUNKBD_CMD_NOCLICK - value);
|
||||
return 0;
|
||||
|
||||
case EV_SND:
|
||||
case SND_BELL:
|
||||
serio_write(sunkbd->serio, SUNKBD_CMD_BELLOFF - value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (code) {
|
||||
|
||||
case SND_CLICK:
|
||||
sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_NOCLICK - value);
|
||||
return 0;
|
||||
|
||||
case SND_BELL:
|
||||
sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_BELLOFF - value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
break;
|
||||
break;
|
||||
}
|
||||
|
||||
return -1;
|
||||
|
@ -183,7 +194,7 @@ static int sunkbd_event(struct input_dev *dev, unsigned int type, unsigned int c
|
|||
static int sunkbd_initialize(struct sunkbd *sunkbd)
|
||||
{
|
||||
sunkbd->reset = -2;
|
||||
sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_RESET);
|
||||
serio_write(sunkbd->serio, SUNKBD_CMD_RESET);
|
||||
wait_event_interruptible_timeout(sunkbd->wait, sunkbd->reset >= 0, HZ);
|
||||
if (sunkbd->reset < 0)
|
||||
return -1;
|
||||
|
@ -192,10 +203,13 @@ static int sunkbd_initialize(struct sunkbd *sunkbd)
|
|||
|
||||
if (sunkbd->type == 4) { /* Type 4 keyboard */
|
||||
sunkbd->layout = -2;
|
||||
sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_LAYOUT);
|
||||
wait_event_interruptible_timeout(sunkbd->wait, sunkbd->layout >= 0, HZ/4);
|
||||
if (sunkbd->layout < 0) return -1;
|
||||
if (sunkbd->layout & SUNKBD_LAYOUT_5_MASK) sunkbd->type = 5;
|
||||
serio_write(sunkbd->serio, SUNKBD_CMD_LAYOUT);
|
||||
wait_event_interruptible_timeout(sunkbd->wait,
|
||||
sunkbd->layout >= 0, HZ / 4);
|
||||
if (sunkbd->layout < 0)
|
||||
return -1;
|
||||
if (sunkbd->layout & SUNKBD_LAYOUT_5_MASK)
|
||||
sunkbd->type = 5;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -212,15 +226,19 @@ static void sunkbd_reinit(struct work_struct *work)
|
|||
|
||||
wait_event_interruptible_timeout(sunkbd->wait, sunkbd->reset >= 0, HZ);
|
||||
|
||||
sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_SETLED);
|
||||
sunkbd->serio->write(sunkbd->serio,
|
||||
(!!test_bit(LED_CAPSL, sunkbd->dev->led) << 3) | (!!test_bit(LED_SCROLLL, sunkbd->dev->led) << 2) |
|
||||
(!!test_bit(LED_COMPOSE, sunkbd->dev->led) << 1) | !!test_bit(LED_NUML, sunkbd->dev->led));
|
||||
sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_NOCLICK - !!test_bit(SND_CLICK, sunkbd->dev->snd));
|
||||
sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_BELLOFF - !!test_bit(SND_BELL, sunkbd->dev->snd));
|
||||
serio_write(sunkbd->serio, SUNKBD_CMD_SETLED);
|
||||
serio_write(sunkbd->serio,
|
||||
(!!test_bit(LED_CAPSL, sunkbd->dev->led) << 3) |
|
||||
(!!test_bit(LED_SCROLLL, sunkbd->dev->led) << 2) |
|
||||
(!!test_bit(LED_COMPOSE, sunkbd->dev->led) << 1) |
|
||||
!!test_bit(LED_NUML, sunkbd->dev->led));
|
||||
serio_write(sunkbd->serio,
|
||||
SUNKBD_CMD_NOCLICK - !!test_bit(SND_CLICK, sunkbd->dev->snd));
|
||||
serio_write(sunkbd->serio,
|
||||
SUNKBD_CMD_BELLOFF - !!test_bit(SND_BELL, sunkbd->dev->snd));
|
||||
}
|
||||
|
||||
static void sunkbd_enable(struct sunkbd *sunkbd, int enable)
|
||||
static void sunkbd_enable(struct sunkbd *sunkbd, bool enable)
|
||||
{
|
||||
serio_pause_rx(sunkbd->serio);
|
||||
sunkbd->enabled = enable;
|
||||
|
@ -228,7 +246,8 @@ static void sunkbd_enable(struct sunkbd *sunkbd, int enable)
|
|||
}
|
||||
|
||||
/*
|
||||
* sunkbd_connect() probes for a Sun keyboard and fills the necessary structures.
|
||||
* sunkbd_connect() probes for a Sun keyboard and fills the necessary
|
||||
* structures.
|
||||
*/
|
||||
|
||||
static int sunkbd_connect(struct serio *serio, struct serio_driver *drv)
|
||||
|
@ -260,7 +279,8 @@ static int sunkbd_connect(struct serio *serio, struct serio_driver *drv)
|
|||
goto fail3;
|
||||
}
|
||||
|
||||
snprintf(sunkbd->name, sizeof(sunkbd->name), "Sun Type %d keyboard", sunkbd->type);
|
||||
snprintf(sunkbd->name, sizeof(sunkbd->name),
|
||||
"Sun Type %d keyboard", sunkbd->type);
|
||||
memcpy(sunkbd->keycode, sunkbd_keycode, sizeof(sunkbd->keycode));
|
||||
|
||||
input_dev->name = sunkbd->name;
|
||||
|
@ -284,11 +304,11 @@ static int sunkbd_connect(struct serio *serio, struct serio_driver *drv)
|
|||
input_dev->keycode = sunkbd->keycode;
|
||||
input_dev->keycodesize = sizeof(unsigned char);
|
||||
input_dev->keycodemax = ARRAY_SIZE(sunkbd_keycode);
|
||||
for (i = 0; i < 128; i++)
|
||||
set_bit(sunkbd->keycode[i], input_dev->keybit);
|
||||
clear_bit(0, input_dev->keybit);
|
||||
for (i = 0; i < ARRAY_SIZE(sunkbd_keycode); i++)
|
||||
__set_bit(sunkbd->keycode[i], input_dev->keybit);
|
||||
__clear_bit(KEY_RESERVED, input_dev->keybit);
|
||||
|
||||
sunkbd_enable(sunkbd, 1);
|
||||
sunkbd_enable(sunkbd, true);
|
||||
|
||||
err = input_register_device(sunkbd->dev);
|
||||
if (err)
|
||||
|
@ -296,7 +316,7 @@ static int sunkbd_connect(struct serio *serio, struct serio_driver *drv)
|
|||
|
||||
return 0;
|
||||
|
||||
fail4: sunkbd_enable(sunkbd, 0);
|
||||
fail4: sunkbd_enable(sunkbd, false);
|
||||
fail3: serio_close(serio);
|
||||
fail2: serio_set_drvdata(serio, NULL);
|
||||
fail1: input_free_device(input_dev);
|
||||
|
@ -312,7 +332,7 @@ static void sunkbd_disconnect(struct serio *serio)
|
|||
{
|
||||
struct sunkbd *sunkbd = serio_get_drvdata(serio);
|
||||
|
||||
sunkbd_enable(sunkbd, 0);
|
||||
sunkbd_enable(sunkbd, false);
|
||||
input_unregister_device(sunkbd->dev);
|
||||
serio_close(serio);
|
||||
serio_set_drvdata(serio, NULL);
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
#define KB_DISCHARGE_DELAY 10
|
||||
#define KB_ACTIVATE_DELAY 10
|
||||
|
||||
static unsigned int tosakbd_keycode[NR_SCANCODES] = {
|
||||
static unsigned short tosakbd_keycode[NR_SCANCODES] = {
|
||||
0,
|
||||
0, KEY_W, 0, 0, 0, KEY_K, KEY_BACKSPACE, KEY_P,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
|
@ -50,9 +50,9 @@ KEY_X, KEY_F, KEY_SPACE, KEY_APOSTROPHE, TOSA_KEY_MAIL, KEY_LEFT, KEY_DOWN, KEY_
|
|||
};
|
||||
|
||||
struct tosakbd {
|
||||
unsigned int keycode[ARRAY_SIZE(tosakbd_keycode)];
|
||||
unsigned short keycode[ARRAY_SIZE(tosakbd_keycode)];
|
||||
struct input_dev *input;
|
||||
int suspended;
|
||||
bool suspended;
|
||||
spinlock_t lock; /* protect kbd scanning */
|
||||
struct timer_list timer;
|
||||
};
|
||||
|
@ -215,7 +215,7 @@ static int tosakbd_suspend(struct platform_device *dev, pm_message_t state)
|
|||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&tosakbd->lock, flags);
|
||||
tosakbd->suspended = 1;
|
||||
tosakbd->suspended = true;
|
||||
spin_unlock_irqrestore(&tosakbd->lock, flags);
|
||||
|
||||
del_timer_sync(&tosakbd->timer);
|
||||
|
@ -227,7 +227,7 @@ static int tosakbd_resume(struct platform_device *dev)
|
|||
{
|
||||
struct tosakbd *tosakbd = platform_get_drvdata(dev);
|
||||
|
||||
tosakbd->suspended = 0;
|
||||
tosakbd->suspended = false;
|
||||
tosakbd_scankeyboard(dev);
|
||||
|
||||
return 0;
|
||||
|
@ -277,14 +277,14 @@ static int __devinit tosakbd_probe(struct platform_device *pdev) {
|
|||
|
||||
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
|
||||
input_dev->keycode = tosakbd->keycode;
|
||||
input_dev->keycodesize = sizeof(unsigned int);
|
||||
input_dev->keycodesize = sizeof(tosakbd->keycode[0]);
|
||||
input_dev->keycodemax = ARRAY_SIZE(tosakbd_keycode);
|
||||
|
||||
memcpy(tosakbd->keycode, tosakbd_keycode, sizeof(tosakbd_keycode));
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(tosakbd_keycode); i++)
|
||||
__set_bit(tosakbd->keycode[i], input_dev->keybit);
|
||||
clear_bit(0, input_dev->keybit);
|
||||
__clear_bit(KEY_RESERVED, input_dev->keybit);
|
||||
|
||||
/* Setup sense interrupts - RisingEdge Detect, sense lines as inputs */
|
||||
for (i = 0; i < TOSA_KEY_SENSE_NUM; i++) {
|
||||
|
@ -344,7 +344,7 @@ static int __devinit tosakbd_probe(struct platform_device *pdev) {
|
|||
" direction for GPIO %d, error %d\n",
|
||||
gpio, error);
|
||||
gpio_free(gpio);
|
||||
goto fail;
|
||||
goto fail2;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -353,7 +353,7 @@ static int __devinit tosakbd_probe(struct platform_device *pdev) {
|
|||
if (error) {
|
||||
printk(KERN_ERR "tosakbd: Unable to register input device, "
|
||||
"error: %d\n", error);
|
||||
goto fail;
|
||||
goto fail2;
|
||||
}
|
||||
|
||||
printk(KERN_INFO "input: Tosa Keyboard Registered\n");
|
||||
|
|
480
drivers/input/keyboard/twl4030_keypad.c
Normal file
480
drivers/input/keyboard/twl4030_keypad.c
Normal file
|
@ -0,0 +1,480 @@
|
|||
/*
|
||||
* twl4030_keypad.c - driver for 8x8 keypad controller in twl4030 chips
|
||||
*
|
||||
* Copyright (C) 2007 Texas Instruments, Inc.
|
||||
* Copyright (C) 2008 Nokia Corporation
|
||||
*
|
||||
* Code re-written for 2430SDP by:
|
||||
* Syed Mohammed Khasim <x0khasim@ti.com>
|
||||
*
|
||||
* Initial Code:
|
||||
* Manjunatha G K <manjugk@ti.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/i2c/twl4030.h>
|
||||
|
||||
|
||||
/*
|
||||
* The TWL4030 family chips include a keypad controller that supports
|
||||
* up to an 8x8 switch matrix. The controller can issue system wakeup
|
||||
* events, since it uses only the always-on 32KiHz oscillator, and has
|
||||
* an internal state machine that decodes pressed keys, including
|
||||
* multi-key combinations.
|
||||
*
|
||||
* This driver lets boards define what keycodes they wish to report for
|
||||
* which scancodes, as part of the "struct twl4030_keypad_data" used in
|
||||
* the probe() routine.
|
||||
*
|
||||
* See the TPS65950 documentation; that's the general availability
|
||||
* version of the TWL5030 second generation part.
|
||||
*/
|
||||
#define TWL4030_MAX_ROWS 8 /* TWL4030 hard limit */
|
||||
#define TWL4030_MAX_COLS 8
|
||||
#define TWL4030_ROW_SHIFT 3
|
||||
#define TWL4030_KEYMAP_SIZE (TWL4030_MAX_ROWS * TWL4030_MAX_COLS)
|
||||
|
||||
struct twl4030_keypad {
|
||||
unsigned short keymap[TWL4030_KEYMAP_SIZE];
|
||||
u16 kp_state[TWL4030_MAX_ROWS];
|
||||
unsigned n_rows;
|
||||
unsigned n_cols;
|
||||
unsigned irq;
|
||||
|
||||
struct device *dbg_dev;
|
||||
struct input_dev *input;
|
||||
};
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
/* arbitrary prescaler value 0..7 */
|
||||
#define PTV_PRESCALER 4
|
||||
|
||||
/* Register Offsets */
|
||||
#define KEYP_CTRL 0x00
|
||||
#define KEYP_DEB 0x01
|
||||
#define KEYP_LONG_KEY 0x02
|
||||
#define KEYP_LK_PTV 0x03
|
||||
#define KEYP_TIMEOUT_L 0x04
|
||||
#define KEYP_TIMEOUT_H 0x05
|
||||
#define KEYP_KBC 0x06
|
||||
#define KEYP_KBR 0x07
|
||||
#define KEYP_SMS 0x08
|
||||
#define KEYP_FULL_CODE_7_0 0x09 /* row 0 column status */
|
||||
#define KEYP_FULL_CODE_15_8 0x0a /* ... row 1 ... */
|
||||
#define KEYP_FULL_CODE_23_16 0x0b
|
||||
#define KEYP_FULL_CODE_31_24 0x0c
|
||||
#define KEYP_FULL_CODE_39_32 0x0d
|
||||
#define KEYP_FULL_CODE_47_40 0x0e
|
||||
#define KEYP_FULL_CODE_55_48 0x0f
|
||||
#define KEYP_FULL_CODE_63_56 0x10
|
||||
#define KEYP_ISR1 0x11
|
||||
#define KEYP_IMR1 0x12
|
||||
#define KEYP_ISR2 0x13
|
||||
#define KEYP_IMR2 0x14
|
||||
#define KEYP_SIR 0x15
|
||||
#define KEYP_EDR 0x16 /* edge triggers */
|
||||
#define KEYP_SIH_CTRL 0x17
|
||||
|
||||
/* KEYP_CTRL_REG Fields */
|
||||
#define KEYP_CTRL_SOFT_NRST BIT(0)
|
||||
#define KEYP_CTRL_SOFTMODEN BIT(1)
|
||||
#define KEYP_CTRL_LK_EN BIT(2)
|
||||
#define KEYP_CTRL_TOE_EN BIT(3)
|
||||
#define KEYP_CTRL_TOLE_EN BIT(4)
|
||||
#define KEYP_CTRL_RP_EN BIT(5)
|
||||
#define KEYP_CTRL_KBD_ON BIT(6)
|
||||
|
||||
/* KEYP_DEB, KEYP_LONG_KEY, KEYP_TIMEOUT_x*/
|
||||
#define KEYP_PERIOD_US(t, prescale) ((t) / (31 << (prescale + 1)) - 1)
|
||||
|
||||
/* KEYP_LK_PTV_REG Fields */
|
||||
#define KEYP_LK_PTV_PTV_SHIFT 5
|
||||
|
||||
/* KEYP_{IMR,ISR,SIR} Fields */
|
||||
#define KEYP_IMR1_MIS BIT(3)
|
||||
#define KEYP_IMR1_TO BIT(2)
|
||||
#define KEYP_IMR1_LK BIT(1)
|
||||
#define KEYP_IMR1_KP BIT(0)
|
||||
|
||||
/* KEYP_EDR Fields */
|
||||
#define KEYP_EDR_KP_FALLING 0x01
|
||||
#define KEYP_EDR_KP_RISING 0x02
|
||||
#define KEYP_EDR_KP_BOTH 0x03
|
||||
#define KEYP_EDR_LK_FALLING 0x04
|
||||
#define KEYP_EDR_LK_RISING 0x08
|
||||
#define KEYP_EDR_TO_FALLING 0x10
|
||||
#define KEYP_EDR_TO_RISING 0x20
|
||||
#define KEYP_EDR_MIS_FALLING 0x40
|
||||
#define KEYP_EDR_MIS_RISING 0x80
|
||||
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
static int twl4030_kpread(struct twl4030_keypad *kp,
|
||||
u8 *data, u32 reg, u8 num_bytes)
|
||||
{
|
||||
int ret = twl4030_i2c_read(TWL4030_MODULE_KEYPAD, data, reg, num_bytes);
|
||||
|
||||
if (ret < 0)
|
||||
dev_warn(kp->dbg_dev,
|
||||
"Couldn't read TWL4030: %X - ret %d[%x]\n",
|
||||
reg, ret, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int twl4030_kpwrite_u8(struct twl4030_keypad *kp, u8 data, u32 reg)
|
||||
{
|
||||
int ret = twl4030_i2c_write_u8(TWL4030_MODULE_KEYPAD, data, reg);
|
||||
|
||||
if (ret < 0)
|
||||
dev_warn(kp->dbg_dev,
|
||||
"Could not write TWL4030: %X - ret %d[%x]\n",
|
||||
reg, ret, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline u16 twl4030_col_xlate(struct twl4030_keypad *kp, u8 col)
|
||||
{
|
||||
/* If all bits in a row are active for all coloumns then
|
||||
* we have that row line connected to gnd. Mark this
|
||||
* key on as if it was on matrix position n_cols (ie
|
||||
* one higher than the size of the matrix).
|
||||
*/
|
||||
if (col == 0xFF)
|
||||
return 1 << kp->n_cols;
|
||||
else
|
||||
return col & ((1 << kp->n_cols) - 1);
|
||||
}
|
||||
|
||||
static int twl4030_read_kp_matrix_state(struct twl4030_keypad *kp, u16 *state)
|
||||
{
|
||||
u8 new_state[TWL4030_MAX_ROWS];
|
||||
int row;
|
||||
int ret = twl4030_kpread(kp, new_state,
|
||||
KEYP_FULL_CODE_7_0, kp->n_rows);
|
||||
if (ret >= 0)
|
||||
for (row = 0; row < kp->n_rows; row++)
|
||||
state[row] = twl4030_col_xlate(kp, new_state[row]);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int twl4030_is_in_ghost_state(struct twl4030_keypad *kp, u16 *key_state)
|
||||
{
|
||||
int i;
|
||||
u16 check = 0;
|
||||
|
||||
for (i = 0; i < kp->n_rows; i++) {
|
||||
u16 col = key_state[i];
|
||||
|
||||
if ((col & check) && hweight16(col) > 1)
|
||||
return 1;
|
||||
|
||||
check |= col;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void twl4030_kp_scan(struct twl4030_keypad *kp, bool release_all)
|
||||
{
|
||||
struct input_dev *input = kp->input;
|
||||
u16 new_state[TWL4030_MAX_ROWS];
|
||||
int col, row;
|
||||
|
||||
if (release_all)
|
||||
memset(new_state, 0, sizeof(new_state));
|
||||
else {
|
||||
/* check for any changes */
|
||||
int ret = twl4030_read_kp_matrix_state(kp, new_state);
|
||||
|
||||
if (ret < 0) /* panic ... */
|
||||
return;
|
||||
|
||||
if (twl4030_is_in_ghost_state(kp, new_state))
|
||||
return;
|
||||
}
|
||||
|
||||
/* check for changes and print those */
|
||||
for (row = 0; row < kp->n_rows; row++) {
|
||||
int changed = new_state[row] ^ kp->kp_state[row];
|
||||
|
||||
if (!changed)
|
||||
continue;
|
||||
|
||||
for (col = 0; col < kp->n_cols; col++) {
|
||||
int code;
|
||||
|
||||
if (!(changed & (1 << col)))
|
||||
continue;
|
||||
|
||||
dev_dbg(kp->dbg_dev, "key [%d:%d] %s\n", row, col,
|
||||
(new_state[row] & (1 << col)) ?
|
||||
"press" : "release");
|
||||
|
||||
code = MATRIX_SCAN_CODE(row, col, TWL4030_ROW_SHIFT);
|
||||
input_event(input, EV_MSC, MSC_SCAN, code);
|
||||
input_report_key(input, kp->keymap[code],
|
||||
new_state[row] & (1 << col));
|
||||
}
|
||||
kp->kp_state[row] = new_state[row];
|
||||
}
|
||||
input_sync(input);
|
||||
}
|
||||
|
||||
/*
|
||||
* Keypad interrupt handler
|
||||
*/
|
||||
static irqreturn_t do_kp_irq(int irq, void *_kp)
|
||||
{
|
||||
struct twl4030_keypad *kp = _kp;
|
||||
u8 reg;
|
||||
int ret;
|
||||
|
||||
#ifdef CONFIG_LOCKDEP
|
||||
/* WORKAROUND for lockdep forcing IRQF_DISABLED on us, which
|
||||
* we don't want and can't tolerate. Although it might be
|
||||
* friendlier not to borrow this thread context...
|
||||
*/
|
||||
local_irq_enable();
|
||||
#endif
|
||||
|
||||
/* Read & Clear TWL4030 pending interrupt */
|
||||
ret = twl4030_kpread(kp, ®, KEYP_ISR1, 1);
|
||||
|
||||
/* Release all keys if I2C has gone bad or
|
||||
* the KEYP has gone to idle state */
|
||||
if (ret >= 0 && (reg & KEYP_IMR1_KP))
|
||||
twl4030_kp_scan(kp, false);
|
||||
else
|
||||
twl4030_kp_scan(kp, true);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int __devinit twl4030_kp_program(struct twl4030_keypad *kp)
|
||||
{
|
||||
u8 reg;
|
||||
int i;
|
||||
|
||||
/* Enable controller, with hardware decoding but not autorepeat */
|
||||
reg = KEYP_CTRL_SOFT_NRST | KEYP_CTRL_SOFTMODEN
|
||||
| KEYP_CTRL_TOE_EN | KEYP_CTRL_KBD_ON;
|
||||
if (twl4030_kpwrite_u8(kp, reg, KEYP_CTRL) < 0)
|
||||
return -EIO;
|
||||
|
||||
/* NOTE: we could use sih_setup() here to package keypad
|
||||
* event sources as four different IRQs ... but we don't.
|
||||
*/
|
||||
|
||||
/* Enable TO rising and KP rising and falling edge detection */
|
||||
reg = KEYP_EDR_KP_BOTH | KEYP_EDR_TO_RISING;
|
||||
if (twl4030_kpwrite_u8(kp, reg, KEYP_EDR) < 0)
|
||||
return -EIO;
|
||||
|
||||
/* Set PTV prescaler Field */
|
||||
reg = (PTV_PRESCALER << KEYP_LK_PTV_PTV_SHIFT);
|
||||
if (twl4030_kpwrite_u8(kp, reg, KEYP_LK_PTV) < 0)
|
||||
return -EIO;
|
||||
|
||||
/* Set key debounce time to 20 ms */
|
||||
i = KEYP_PERIOD_US(20000, PTV_PRESCALER);
|
||||
if (twl4030_kpwrite_u8(kp, i, KEYP_DEB) < 0)
|
||||
return -EIO;
|
||||
|
||||
/* Set timeout period to 100 ms */
|
||||
i = KEYP_PERIOD_US(200000, PTV_PRESCALER);
|
||||
if (twl4030_kpwrite_u8(kp, (i & 0xFF), KEYP_TIMEOUT_L) < 0)
|
||||
return -EIO;
|
||||
|
||||
if (twl4030_kpwrite_u8(kp, (i >> 8), KEYP_TIMEOUT_H) < 0)
|
||||
return -EIO;
|
||||
|
||||
/*
|
||||
* Enable Clear-on-Read; disable remembering events that fire
|
||||
* after the IRQ but before our handler acks (reads) them,
|
||||
*/
|
||||
reg = TWL4030_SIH_CTRL_COR_MASK | TWL4030_SIH_CTRL_PENDDIS_MASK;
|
||||
if (twl4030_kpwrite_u8(kp, reg, KEYP_SIH_CTRL) < 0)
|
||||
return -EIO;
|
||||
|
||||
/* initialize key state; irqs update it from here on */
|
||||
if (twl4030_read_kp_matrix_state(kp, kp->kp_state) < 0)
|
||||
return -EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Registers keypad device with input subsystem
|
||||
* and configures TWL4030 keypad registers
|
||||
*/
|
||||
static int __devinit twl4030_kp_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct twl4030_keypad_data *pdata = pdev->dev.platform_data;
|
||||
const struct matrix_keymap_data *keymap_data = pdata->keymap_data;
|
||||
struct twl4030_keypad *kp;
|
||||
struct input_dev *input;
|
||||
u8 reg;
|
||||
int error;
|
||||
|
||||
if (!pdata || !pdata->rows || !pdata->cols ||
|
||||
pdata->rows > TWL4030_MAX_ROWS || pdata->cols > TWL4030_MAX_COLS) {
|
||||
dev_err(&pdev->dev, "Invalid platform_data\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
kp = kzalloc(sizeof(*kp), GFP_KERNEL);
|
||||
input = input_allocate_device();
|
||||
if (!kp || !input) {
|
||||
error = -ENOMEM;
|
||||
goto err1;
|
||||
}
|
||||
|
||||
/* Get the debug Device */
|
||||
kp->dbg_dev = &pdev->dev;
|
||||
kp->input = input;
|
||||
|
||||
kp->n_rows = pdata->rows;
|
||||
kp->n_cols = pdata->cols;
|
||||
kp->irq = platform_get_irq(pdev, 0);
|
||||
|
||||
/* setup input device */
|
||||
__set_bit(EV_KEY, input->evbit);
|
||||
|
||||
/* Enable auto repeat feature of Linux input subsystem */
|
||||
if (pdata->rep)
|
||||
__set_bit(EV_REP, input->evbit);
|
||||
|
||||
input_set_capability(input, EV_MSC, MSC_SCAN);
|
||||
|
||||
input->name = "TWL4030 Keypad";
|
||||
input->phys = "twl4030_keypad/input0";
|
||||
input->dev.parent = &pdev->dev;
|
||||
|
||||
input->id.bustype = BUS_HOST;
|
||||
input->id.vendor = 0x0001;
|
||||
input->id.product = 0x0001;
|
||||
input->id.version = 0x0003;
|
||||
|
||||
input->keycode = kp->keymap;
|
||||
input->keycodesize = sizeof(kp->keymap[0]);
|
||||
input->keycodemax = ARRAY_SIZE(kp->keymap);
|
||||
|
||||
matrix_keypad_build_keymap(keymap_data, TWL4030_ROW_SHIFT,
|
||||
input->keycode, input->keybit);
|
||||
|
||||
error = input_register_device(input);
|
||||
if (error) {
|
||||
dev_err(kp->dbg_dev,
|
||||
"Unable to register twl4030 keypad device\n");
|
||||
goto err1;
|
||||
}
|
||||
|
||||
error = twl4030_kp_program(kp);
|
||||
if (error)
|
||||
goto err2;
|
||||
|
||||
/*
|
||||
* This ISR will always execute in kernel thread context because of
|
||||
* the need to access the TWL4030 over the I2C bus.
|
||||
*
|
||||
* NOTE: we assume this host is wired to TWL4040 INT1, not INT2 ...
|
||||
*/
|
||||
error = request_irq(kp->irq, do_kp_irq, 0, pdev->name, kp);
|
||||
if (error) {
|
||||
dev_info(kp->dbg_dev, "request_irq failed for irq no=%d\n",
|
||||
kp->irq);
|
||||
goto err3;
|
||||
}
|
||||
|
||||
/* Enable KP and TO interrupts now. */
|
||||
reg = (u8) ~(KEYP_IMR1_KP | KEYP_IMR1_TO);
|
||||
if (twl4030_kpwrite_u8(kp, reg, KEYP_IMR1)) {
|
||||
error = -EIO;
|
||||
goto err4;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, kp);
|
||||
return 0;
|
||||
|
||||
err4:
|
||||
/* mask all events - we don't care about the result */
|
||||
(void) twl4030_kpwrite_u8(kp, 0xff, KEYP_IMR1);
|
||||
err3:
|
||||
free_irq(kp->irq, NULL);
|
||||
err2:
|
||||
input_unregister_device(input);
|
||||
input = NULL;
|
||||
err1:
|
||||
input_free_device(input);
|
||||
kfree(kp);
|
||||
return error;
|
||||
}
|
||||
|
||||
static int __devexit twl4030_kp_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct twl4030_keypad *kp = platform_get_drvdata(pdev);
|
||||
|
||||
free_irq(kp->irq, kp);
|
||||
input_unregister_device(kp->input);
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
kfree(kp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* NOTE: twl4030 are multi-function devices connected via I2C.
|
||||
* So this device is a child of an I2C parent, thus it needs to
|
||||
* support unplug/replug (which most platform devices don't).
|
||||
*/
|
||||
|
||||
static struct platform_driver twl4030_kp_driver = {
|
||||
.probe = twl4030_kp_probe,
|
||||
.remove = __devexit_p(twl4030_kp_remove),
|
||||
.driver = {
|
||||
.name = "twl4030_keypad",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init twl4030_kp_init(void)
|
||||
{
|
||||
return platform_driver_register(&twl4030_kp_driver);
|
||||
}
|
||||
module_init(twl4030_kp_init);
|
||||
|
||||
static void __exit twl4030_kp_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&twl4030_kp_driver);
|
||||
}
|
||||
module_exit(twl4030_kp_exit);
|
||||
|
||||
MODULE_AUTHOR("Texas Instruments");
|
||||
MODULE_DESCRIPTION("TWL4030 Keypad Driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:twl4030_keypad");
|
||||
|
281
drivers/input/keyboard/w90p910_keypad.c
Normal file
281
drivers/input/keyboard/w90p910_keypad.c
Normal file
|
@ -0,0 +1,281 @@
|
|||
/*
|
||||
* Copyright (c) 2008-2009 Nuvoton technology corporation.
|
||||
*
|
||||
* Wan ZongShun <mcuos.com@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation;version 2 of the License.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
#include <mach/w90p910_keypad.h>
|
||||
|
||||
/* Keypad Interface Control Registers */
|
||||
#define KPI_CONF 0x00
|
||||
#define KPI_3KCONF 0x04
|
||||
#define KPI_LPCONF 0x08
|
||||
#define KPI_STATUS 0x0C
|
||||
|
||||
#define IS1KEY (0x01 << 16)
|
||||
#define INTTR (0x01 << 21)
|
||||
#define KEY0R (0x0f << 3)
|
||||
#define KEY0C 0x07
|
||||
#define DEBOUNCE_BIT 0x08
|
||||
#define KSIZE0 (0x01 << 16)
|
||||
#define KSIZE1 (0x01 << 17)
|
||||
#define KPSEL (0x01 << 19)
|
||||
#define ENKP (0x01 << 18)
|
||||
|
||||
#define KGET_RAW(n) (((n) & KEY0R) >> 3)
|
||||
#define KGET_COLUMN(n) ((n) & KEY0C)
|
||||
|
||||
#define W90P910_MAX_KEY_NUM (8 * 8)
|
||||
#define W90P910_ROW_SHIFT 3
|
||||
|
||||
struct w90p910_keypad {
|
||||
const struct w90p910_keypad_platform_data *pdata;
|
||||
struct clk *clk;
|
||||
struct input_dev *input_dev;
|
||||
void __iomem *mmio_base;
|
||||
int irq;
|
||||
unsigned short keymap[W90P910_MAX_KEY_NUM];
|
||||
};
|
||||
|
||||
static void w90p910_keypad_scan_matrix(struct w90p910_keypad *keypad,
|
||||
unsigned int status)
|
||||
{
|
||||
struct input_dev *input_dev = keypad->input_dev;
|
||||
unsigned int row = KGET_RAW(status);
|
||||
unsigned int col = KGET_COLUMN(status);
|
||||
unsigned int code = MATRIX_SCAN_CODE(row, col, W90P910_ROW_SHIFT);
|
||||
unsigned int key = keypad->keymap[code];
|
||||
|
||||
input_event(input_dev, EV_MSC, MSC_SCAN, code);
|
||||
input_report_key(input_dev, key, 1);
|
||||
input_sync(input_dev);
|
||||
|
||||
input_event(input_dev, EV_MSC, MSC_SCAN, code);
|
||||
input_report_key(input_dev, key, 0);
|
||||
input_sync(input_dev);
|
||||
}
|
||||
|
||||
static irqreturn_t w90p910_keypad_irq_handler(int irq, void *dev_id)
|
||||
{
|
||||
struct w90p910_keypad *keypad = dev_id;
|
||||
unsigned int kstatus, val;
|
||||
|
||||
kstatus = __raw_readl(keypad->mmio_base + KPI_STATUS);
|
||||
|
||||
val = INTTR | IS1KEY;
|
||||
|
||||
if (kstatus & val)
|
||||
w90p910_keypad_scan_matrix(keypad, kstatus);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int w90p910_keypad_open(struct input_dev *dev)
|
||||
{
|
||||
struct w90p910_keypad *keypad = input_get_drvdata(dev);
|
||||
const struct w90p910_keypad_platform_data *pdata = keypad->pdata;
|
||||
unsigned int val, config;
|
||||
|
||||
/* Enable unit clock */
|
||||
clk_enable(keypad->clk);
|
||||
|
||||
val = __raw_readl(keypad->mmio_base + KPI_CONF);
|
||||
val |= (KPSEL | ENKP);
|
||||
val &= ~(KSIZE0 | KSIZE1);
|
||||
|
||||
config = pdata->prescale | (pdata->debounce << DEBOUNCE_BIT);
|
||||
|
||||
val |= config;
|
||||
|
||||
__raw_writel(val, keypad->mmio_base + KPI_CONF);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void w90p910_keypad_close(struct input_dev *dev)
|
||||
{
|
||||
struct w90p910_keypad *keypad = input_get_drvdata(dev);
|
||||
|
||||
/* Disable clock unit */
|
||||
clk_disable(keypad->clk);
|
||||
}
|
||||
|
||||
static int __devinit w90p910_keypad_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct w90p910_keypad_platform_data *pdata =
|
||||
pdev->dev.platform_data;
|
||||
const struct matrix_keymap_data *keymap_data;
|
||||
struct w90p910_keypad *keypad;
|
||||
struct input_dev *input_dev;
|
||||
struct resource *res;
|
||||
int irq;
|
||||
int error;
|
||||
|
||||
if (!pdata) {
|
||||
dev_err(&pdev->dev, "no platform data defined\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
keymap_data = pdata->keymap_data;
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
dev_err(&pdev->dev, "failed to get keypad irq\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
keypad = kzalloc(sizeof(struct w90p910_keypad), GFP_KERNEL);
|
||||
input_dev = input_allocate_device();
|
||||
if (!keypad || !input_dev) {
|
||||
dev_err(&pdev->dev, "failed to allocate driver data\n");
|
||||
error = -ENOMEM;
|
||||
goto failed_free;
|
||||
}
|
||||
|
||||
keypad->pdata = pdata;
|
||||
keypad->input_dev = input_dev;
|
||||
keypad->irq = irq;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (res == NULL) {
|
||||
dev_err(&pdev->dev, "failed to get I/O memory\n");
|
||||
error = -ENXIO;
|
||||
goto failed_free;
|
||||
}
|
||||
|
||||
res = request_mem_region(res->start, resource_size(res), pdev->name);
|
||||
if (res == NULL) {
|
||||
dev_err(&pdev->dev, "failed to request I/O memory\n");
|
||||
error = -EBUSY;
|
||||
goto failed_free;
|
||||
}
|
||||
|
||||
keypad->mmio_base = ioremap(res->start, resource_size(res));
|
||||
if (keypad->mmio_base == NULL) {
|
||||
dev_err(&pdev->dev, "failed to remap I/O memory\n");
|
||||
error = -ENXIO;
|
||||
goto failed_free_res;
|
||||
}
|
||||
|
||||
keypad->clk = clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(keypad->clk)) {
|
||||
dev_err(&pdev->dev, "failed to get keypad clock\n");
|
||||
error = PTR_ERR(keypad->clk);
|
||||
goto failed_free_io;
|
||||
}
|
||||
|
||||
/* set multi-function pin for w90p910 kpi. */
|
||||
mfp_set_groupi(&pdev->dev);
|
||||
|
||||
input_dev->name = pdev->name;
|
||||
input_dev->id.bustype = BUS_HOST;
|
||||
input_dev->open = w90p910_keypad_open;
|
||||
input_dev->close = w90p910_keypad_close;
|
||||
input_dev->dev.parent = &pdev->dev;
|
||||
|
||||
input_dev->keycode = keypad->keymap;
|
||||
input_dev->keycodesize = sizeof(keypad->keymap[0]);
|
||||
input_dev->keycodemax = ARRAY_SIZE(keypad->keymap);
|
||||
|
||||
input_set_drvdata(input_dev, keypad);
|
||||
|
||||
input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
|
||||
input_set_capability(input_dev, EV_MSC, MSC_SCAN);
|
||||
|
||||
matrix_keypad_build_keymap(keymap_data, W90P910_ROW_SHIFT,
|
||||
input_dev->keycode, input_dev->keybit);
|
||||
|
||||
error = request_irq(keypad->irq, w90p910_keypad_irq_handler,
|
||||
IRQF_DISABLED, pdev->name, keypad);
|
||||
if (error) {
|
||||
dev_err(&pdev->dev, "failed to request IRQ\n");
|
||||
goto failed_put_clk;
|
||||
}
|
||||
|
||||
/* Register the input device */
|
||||
error = input_register_device(input_dev);
|
||||
if (error) {
|
||||
dev_err(&pdev->dev, "failed to register input device\n");
|
||||
goto failed_free_irq;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, keypad);
|
||||
return 0;
|
||||
|
||||
failed_free_irq:
|
||||
free_irq(irq, pdev);
|
||||
failed_put_clk:
|
||||
clk_put(keypad->clk);
|
||||
failed_free_io:
|
||||
iounmap(keypad->mmio_base);
|
||||
failed_free_res:
|
||||
release_mem_region(res->start, resource_size(res));
|
||||
failed_free:
|
||||
input_free_device(input_dev);
|
||||
kfree(keypad);
|
||||
return error;
|
||||
}
|
||||
|
||||
static int __devexit w90p910_keypad_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct w90p910_keypad *keypad = platform_get_drvdata(pdev);
|
||||
struct resource *res;
|
||||
|
||||
free_irq(keypad->irq, pdev);
|
||||
|
||||
clk_put(keypad->clk);
|
||||
|
||||
input_unregister_device(keypad->input_dev);
|
||||
|
||||
iounmap(keypad->mmio_base);
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
release_mem_region(res->start, resource_size(res));
|
||||
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
kfree(keypad);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver w90p910_keypad_driver = {
|
||||
.probe = w90p910_keypad_probe,
|
||||
.remove = __devexit_p(w90p910_keypad_remove),
|
||||
.driver = {
|
||||
.name = "nuc900-keypad",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init w90p910_keypad_init(void)
|
||||
{
|
||||
return platform_driver_register(&w90p910_keypad_driver);
|
||||
}
|
||||
|
||||
static void __exit w90p910_keypad_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&w90p910_keypad_driver);
|
||||
}
|
||||
|
||||
module_init(w90p910_keypad_init);
|
||||
module_exit(w90p910_keypad_exit);
|
||||
|
||||
MODULE_AUTHOR("Wan ZongShun <mcuos.com@gmail.com>");
|
||||
MODULE_DESCRIPTION("w90p910 keypad driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:nuc900-keypad");
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
283
drivers/input/misc/bfin_rotary.c
Normal file
283
drivers/input/misc/bfin_rotary.c
Normal file
|
@ -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");
|
|
@ -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);
|
||||
|
|
|
@ -23,30 +23,16 @@
|
|||
* 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;
|
||||
|
||||
|
|
|
@ -243,9 +243,9 @@ enum { KE_END, KE_KEY, KE_SW, KE_WIFI, KE_BLUETOOTH };
|
|||
#define FE_UNTESTED 0x80
|
||||
|
||||
static struct key_entry *keymap; /* = NULL; Current key map */
|
||||
static int have_wifi;
|
||||
static int have_bluetooth;
|
||||
static int have_leds;
|
||||
static bool have_wifi;
|
||||
static bool have_bluetooth;
|
||||
static int leds_present; /* bitmask of leds present */
|
||||
|
||||
static int __init dmi_matched(const struct dmi_system_id *dmi)
|
||||
{
|
||||
|
@ -254,11 +254,11 @@ static int __init dmi_matched(const struct dmi_system_id *dmi)
|
|||
keymap = dmi->driver_data;
|
||||
for (key = keymap; key->type != KE_END; key++) {
|
||||
if (key->type == KE_WIFI)
|
||||
have_wifi = 1;
|
||||
have_wifi = true;
|
||||
else if (key->type == KE_BLUETOOTH)
|
||||
have_bluetooth = 1;
|
||||
have_bluetooth = true;
|
||||
}
|
||||
have_leds = key->code & (FE_MAIL_LED | FE_WIFI_LED);
|
||||
leds_present = key->code & (FE_MAIL_LED | FE_WIFI_LED);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@ -611,10 +611,24 @@ static struct key_entry keymap_wistron_generic[] __initdata = {
|
|||
{ KE_END, 0 }
|
||||
};
|
||||
|
||||
static struct key_entry keymap_aopen_1557[] __initdata = {
|
||||
{ KE_KEY, 0x01, {KEY_HELP} },
|
||||
{ KE_KEY, 0x11, {KEY_PROG1} },
|
||||
{ KE_KEY, 0x12, {KEY_PROG2} },
|
||||
{ KE_WIFI, 0x30 },
|
||||
{ KE_KEY, 0x22, {KEY_REWIND} },
|
||||
{ KE_KEY, 0x23, {KEY_FORWARD} },
|
||||
{ KE_KEY, 0x24, {KEY_PLAYPAUSE} },
|
||||
{ KE_KEY, 0x25, {KEY_STOPCD} },
|
||||
{ KE_KEY, 0x31, {KEY_MAIL} },
|
||||
{ KE_KEY, 0x36, {KEY_WWW} },
|
||||
{ KE_END, 0 }
|
||||
};
|
||||
|
||||
static struct key_entry keymap_prestigio[] __initdata = {
|
||||
{ KE_KEY, 0x11, {KEY_PROG1} },
|
||||
{ KE_KEY, 0x12, {KEY_PROG2} },
|
||||
{ KE_WIFI, 0x30 },
|
||||
{ KE_WIFI, 0x30 },
|
||||
{ KE_KEY, 0x22, {KEY_REWIND} },
|
||||
{ KE_KEY, 0x23, {KEY_FORWARD} },
|
||||
{ KE_KEY, 0x24, {KEY_PLAYPAUSE} },
|
||||
|
@ -985,6 +999,8 @@ static int __init select_keymap(void)
|
|||
if (keymap_name != NULL) {
|
||||
if (strcmp (keymap_name, "1557/MS2141") == 0)
|
||||
keymap = keymap_wistron_ms2141;
|
||||
else if (strcmp (keymap_name, "aopen1557") == 0)
|
||||
keymap = keymap_aopen_1557;
|
||||
else if (strcmp (keymap_name, "prestigio") == 0)
|
||||
keymap = keymap_prestigio;
|
||||
else if (strcmp (keymap_name, "generic") == 0)
|
||||
|
@ -1009,8 +1025,8 @@ static int __init select_keymap(void)
|
|||
|
||||
static struct input_polled_dev *wistron_idev;
|
||||
static unsigned long jiffies_last_press;
|
||||
static int wifi_enabled;
|
||||
static int bluetooth_enabled;
|
||||
static bool wifi_enabled;
|
||||
static bool bluetooth_enabled;
|
||||
|
||||
static void report_key(struct input_dev *dev, unsigned int keycode)
|
||||
{
|
||||
|
@ -1053,24 +1069,24 @@ static struct led_classdev wistron_wifi_led = {
|
|||
|
||||
static void __devinit wistron_led_init(struct device *parent)
|
||||
{
|
||||
if (have_leds & FE_WIFI_LED) {
|
||||
if (leds_present & FE_WIFI_LED) {
|
||||
u16 wifi = bios_get_default_setting(WIFI);
|
||||
if (wifi & 1) {
|
||||
wistron_wifi_led.brightness = (wifi & 2) ? LED_FULL : LED_OFF;
|
||||
if (led_classdev_register(parent, &wistron_wifi_led))
|
||||
have_leds &= ~FE_WIFI_LED;
|
||||
leds_present &= ~FE_WIFI_LED;
|
||||
else
|
||||
bios_set_state(WIFI, wistron_wifi_led.brightness);
|
||||
|
||||
} else
|
||||
have_leds &= ~FE_WIFI_LED;
|
||||
leds_present &= ~FE_WIFI_LED;
|
||||
}
|
||||
|
||||
if (have_leds & FE_MAIL_LED) {
|
||||
if (leds_present & FE_MAIL_LED) {
|
||||
/* bios_get_default_setting(MAIL) always retuns 0, so just turn the led off */
|
||||
wistron_mail_led.brightness = LED_OFF;
|
||||
if (led_classdev_register(parent, &wistron_mail_led))
|
||||
have_leds &= ~FE_MAIL_LED;
|
||||
leds_present &= ~FE_MAIL_LED;
|
||||
else
|
||||
bios_set_state(MAIL_LED, wistron_mail_led.brightness);
|
||||
}
|
||||
|
@ -1078,28 +1094,28 @@ static void __devinit wistron_led_init(struct device *parent)
|
|||
|
||||
static void __devexit wistron_led_remove(void)
|
||||
{
|
||||
if (have_leds & FE_MAIL_LED)
|
||||
if (leds_present & FE_MAIL_LED)
|
||||
led_classdev_unregister(&wistron_mail_led);
|
||||
|
||||
if (have_leds & FE_WIFI_LED)
|
||||
if (leds_present & FE_WIFI_LED)
|
||||
led_classdev_unregister(&wistron_wifi_led);
|
||||
}
|
||||
|
||||
static inline void wistron_led_suspend(void)
|
||||
{
|
||||
if (have_leds & FE_MAIL_LED)
|
||||
if (leds_present & FE_MAIL_LED)
|
||||
led_classdev_suspend(&wistron_mail_led);
|
||||
|
||||
if (have_leds & FE_WIFI_LED)
|
||||
if (leds_present & FE_WIFI_LED)
|
||||
led_classdev_suspend(&wistron_wifi_led);
|
||||
}
|
||||
|
||||
static inline void wistron_led_resume(void)
|
||||
{
|
||||
if (have_leds & FE_MAIL_LED)
|
||||
if (leds_present & FE_MAIL_LED)
|
||||
led_classdev_resume(&wistron_mail_led);
|
||||
|
||||
if (have_leds & FE_WIFI_LED)
|
||||
if (leds_present & FE_WIFI_LED)
|
||||
led_classdev_resume(&wistron_wifi_led);
|
||||
}
|
||||
|
||||
|
@ -1312,7 +1328,7 @@ static int __devinit wistron_probe(struct platform_device *dev)
|
|||
if (have_wifi) {
|
||||
u16 wifi = bios_get_default_setting(WIFI);
|
||||
if (wifi & 1)
|
||||
wifi_enabled = (wifi & 2) ? 1 : 0;
|
||||
wifi_enabled = wifi & 2;
|
||||
else
|
||||
have_wifi = 0;
|
||||
|
||||
|
@ -1323,15 +1339,16 @@ static int __devinit wistron_probe(struct platform_device *dev)
|
|||
if (have_bluetooth) {
|
||||
u16 bt = bios_get_default_setting(BLUETOOTH);
|
||||
if (bt & 1)
|
||||
bluetooth_enabled = (bt & 2) ? 1 : 0;
|
||||
bluetooth_enabled = bt & 2;
|
||||
else
|
||||
have_bluetooth = 0;
|
||||
have_bluetooth = false;
|
||||
|
||||
if (have_bluetooth)
|
||||
bios_set_state(BLUETOOTH, bluetooth_enabled);
|
||||
}
|
||||
|
||||
wistron_led_init(&dev->dev);
|
||||
|
||||
err = setup_input_dev();
|
||||
if (err) {
|
||||
bios_detach();
|
||||
|
@ -1352,7 +1369,7 @@ static int __devexit wistron_remove(struct platform_device *dev)
|
|||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int wistron_suspend(struct platform_device *dev, pm_message_t state)
|
||||
static int wistron_suspend(struct device *dev)
|
||||
{
|
||||
if (have_wifi)
|
||||
bios_set_state(WIFI, 0);
|
||||
|
@ -1361,10 +1378,11 @@ static int wistron_suspend(struct platform_device *dev, pm_message_t state)
|
|||
bios_set_state(BLUETOOTH, 0);
|
||||
|
||||
wistron_led_suspend();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wistron_resume(struct platform_device *dev)
|
||||
static int wistron_resume(struct device *dev)
|
||||
{
|
||||
if (have_wifi)
|
||||
bios_set_state(WIFI, wifi_enabled);
|
||||
|
@ -1373,24 +1391,30 @@ static int wistron_resume(struct platform_device *dev)
|
|||
bios_set_state(BLUETOOTH, bluetooth_enabled);
|
||||
|
||||
wistron_led_resume();
|
||||
|
||||
poll_bios(true);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#define wistron_suspend NULL
|
||||
#define wistron_resume NULL
|
||||
|
||||
static const struct dev_pm_ops wistron_pm_ops = {
|
||||
.suspend = wistron_suspend,
|
||||
.resume = wistron_resume,
|
||||
.poweroff = wistron_suspend,
|
||||
.restore = wistron_resume,
|
||||
};
|
||||
#endif
|
||||
|
||||
static struct platform_driver wistron_driver = {
|
||||
.driver = {
|
||||
.name = "wistron-bios",
|
||||
.owner = THIS_MODULE,
|
||||
#if CONFIG_PM
|
||||
.pm = &wistron_pm_ops,
|
||||
#endif
|
||||
},
|
||||
.probe = wistron_probe,
|
||||
.remove = __devexit_p(wistron_remove),
|
||||
.suspend = wistron_suspend,
|
||||
.resume = wistron_resume,
|
||||
};
|
||||
|
||||
static int __init wb_module_init(void)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -279,7 +279,7 @@ static const struct alps_model_info *alps_get_model(struct psmouse *psmouse, int
|
|||
* subsequent commands. It looks like glidepad is behind stickpointer,
|
||||
* I'd thought it would be other way around...
|
||||
*/
|
||||
static int alps_passthrough_mode(struct psmouse *psmouse, int enable)
|
||||
static int alps_passthrough_mode(struct psmouse *psmouse, bool enable)
|
||||
{
|
||||
struct ps2dev *ps2dev = &psmouse->ps2dev;
|
||||
int cmd = enable ? PSMOUSE_CMD_SETSCALE21 : PSMOUSE_CMD_SETSCALE11;
|
||||
|
@ -367,16 +367,16 @@ static int alps_poll(struct psmouse *psmouse)
|
|||
{
|
||||
struct alps_data *priv = psmouse->private;
|
||||
unsigned char buf[6];
|
||||
int poll_failed;
|
||||
bool poll_failed;
|
||||
|
||||
if (priv->i->flags & ALPS_PASS)
|
||||
alps_passthrough_mode(psmouse, 1);
|
||||
alps_passthrough_mode(psmouse, true);
|
||||
|
||||
poll_failed = ps2_command(&psmouse->ps2dev, buf,
|
||||
PSMOUSE_CMD_POLL | (psmouse->pktsize << 8)) < 0;
|
||||
|
||||
if (priv->i->flags & ALPS_PASS)
|
||||
alps_passthrough_mode(psmouse, 0);
|
||||
alps_passthrough_mode(psmouse, false);
|
||||
|
||||
if (poll_failed || (buf[0] & priv->i->mask0) != priv->i->byte0)
|
||||
return -1;
|
||||
|
@ -401,10 +401,12 @@ static int alps_hw_init(struct psmouse *psmouse, int *version)
|
|||
if (!priv->i)
|
||||
return -1;
|
||||
|
||||
if ((priv->i->flags & ALPS_PASS) && alps_passthrough_mode(psmouse, 1))
|
||||
if ((priv->i->flags & ALPS_PASS) &&
|
||||
alps_passthrough_mode(psmouse, true)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (alps_tap_mode(psmouse, 1)) {
|
||||
if (alps_tap_mode(psmouse, true)) {
|
||||
printk(KERN_WARNING "alps.c: Failed to enable hardware tapping\n");
|
||||
return -1;
|
||||
}
|
||||
|
@ -414,8 +416,10 @@ static int alps_hw_init(struct psmouse *psmouse, int *version)
|
|||
return -1;
|
||||
}
|
||||
|
||||
if ((priv->i->flags & ALPS_PASS) && alps_passthrough_mode(psmouse, 0))
|
||||
if ((priv->i->flags & ALPS_PASS) &&
|
||||
alps_passthrough_mode(psmouse, false)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* ALPS needs stream mode, otherwise it won't report any data */
|
||||
if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETSTREAM)) {
|
||||
|
@ -519,7 +523,7 @@ int alps_init(struct psmouse *psmouse)
|
|||
return -1;
|
||||
}
|
||||
|
||||
int alps_detect(struct psmouse *psmouse, int set_properties)
|
||||
int alps_detect(struct psmouse *psmouse, bool set_properties)
|
||||
{
|
||||
int version;
|
||||
const struct alps_model_info *model;
|
||||
|
|
|
@ -26,10 +26,10 @@ struct alps_data {
|
|||
};
|
||||
|
||||
#ifdef CONFIG_MOUSE_PS2_ALPS
|
||||
int alps_detect(struct psmouse *psmouse, int set_properties);
|
||||
int alps_detect(struct psmouse *psmouse, bool set_properties);
|
||||
int alps_init(struct psmouse *psmouse);
|
||||
#else
|
||||
inline int alps_detect(struct psmouse *psmouse, int set_properties)
|
||||
inline int alps_detect(struct psmouse *psmouse, bool set_properties)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
|
|
@ -317,7 +317,7 @@ static int report_tp_state(struct bcm5974 *dev, int size)
|
|||
const struct tp_finger *f;
|
||||
struct input_dev *input = dev->input;
|
||||
int raw_p, raw_w, raw_x, raw_y, raw_n;
|
||||
int ptest = 0, origin = 0, ibt = 0, nmin = 0, nmax = 0;
|
||||
int ptest, origin, ibt = 0, nmin = 0, nmax = 0;
|
||||
int abs_p = 0, abs_w = 0, abs_x = 0, abs_y = 0;
|
||||
|
||||
if (size < c->tp_offset || (size - c->tp_offset) % SIZEOF_FINGER != 0)
|
||||
|
@ -345,21 +345,22 @@ static int report_tp_state(struct bcm5974 *dev, int size)
|
|||
/* set the integrated button if applicable */
|
||||
if (c->tp_type == TYPE2)
|
||||
ibt = raw2int(dev->tp_data[BUTTON_TYPE2]);
|
||||
}
|
||||
|
||||
/* while tracking finger still valid, count all fingers */
|
||||
if (ptest > PRESSURE_LOW && origin) {
|
||||
abs_p = ptest;
|
||||
abs_w = int2bound(&c->w, raw_w);
|
||||
abs_x = int2bound(&c->x, raw_x - c->x.devmin);
|
||||
abs_y = int2bound(&c->y, c->y.devmax - raw_y);
|
||||
while (raw_n--) {
|
||||
ptest = int2bound(&c->p, raw2int(f->force_major));
|
||||
if (ptest > PRESSURE_LOW)
|
||||
nmax++;
|
||||
if (ptest > PRESSURE_HIGH)
|
||||
nmin++;
|
||||
f++;
|
||||
/* while tracking finger still valid, count all fingers */
|
||||
if (ptest > PRESSURE_LOW && origin) {
|
||||
abs_p = ptest;
|
||||
abs_w = int2bound(&c->w, raw_w);
|
||||
abs_x = int2bound(&c->x, raw_x - c->x.devmin);
|
||||
abs_y = int2bound(&c->y, c->y.devmax - raw_y);
|
||||
while (raw_n--) {
|
||||
ptest = int2bound(&c->p,
|
||||
raw2int(f->force_major));
|
||||
if (ptest > PRESSURE_LOW)
|
||||
nmax++;
|
||||
if (ptest > PRESSURE_HIGH)
|
||||
nmin++;
|
||||
f++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -553,7 +553,7 @@ static struct attribute_group elantech_attr_group = {
|
|||
/*
|
||||
* Use magic knock to detect Elantech touchpad
|
||||
*/
|
||||
int elantech_detect(struct psmouse *psmouse, int set_properties)
|
||||
int elantech_detect(struct psmouse *psmouse, bool set_properties)
|
||||
{
|
||||
struct ps2dev *ps2dev = &psmouse->ps2dev;
|
||||
unsigned char param[3];
|
||||
|
|
|
@ -109,10 +109,10 @@ struct elantech_data {
|
|||
};
|
||||
|
||||
#ifdef CONFIG_MOUSE_PS2_ELANTECH
|
||||
int elantech_detect(struct psmouse *psmouse, int set_properties);
|
||||
int elantech_detect(struct psmouse *psmouse, bool set_properties);
|
||||
int elantech_init(struct psmouse *psmouse);
|
||||
#else
|
||||
static inline int elantech_detect(struct psmouse *psmouse, int set_properties)
|
||||
static inline int elantech_detect(struct psmouse *psmouse, bool set_properties)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
|
|
@ -367,7 +367,36 @@ static ssize_t hgpk_set_powered(struct psmouse *psmouse, void *data,
|
|||
}
|
||||
|
||||
__PSMOUSE_DEFINE_ATTR(powered, S_IWUSR | S_IRUGO, NULL,
|
||||
hgpk_show_powered, hgpk_set_powered, 0);
|
||||
hgpk_show_powered, hgpk_set_powered, false);
|
||||
|
||||
static ssize_t hgpk_trigger_recal_show(struct psmouse *psmouse,
|
||||
void *data, char *buf)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static ssize_t hgpk_trigger_recal(struct psmouse *psmouse, void *data,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct hgpk_data *priv = psmouse->private;
|
||||
unsigned long value;
|
||||
int err;
|
||||
|
||||
err = strict_strtoul(buf, 10, &value);
|
||||
if (err || value != 1)
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* We queue work instead of doing recalibration right here
|
||||
* to avoid adding locking to to hgpk_force_recalibrate()
|
||||
* since workqueue provides serialization.
|
||||
*/
|
||||
psmouse_queue_work(psmouse, &priv->recalib_wq, 0);
|
||||
return count;
|
||||
}
|
||||
|
||||
__PSMOUSE_DEFINE_ATTR(recalibrate, S_IWUSR | S_IRUGO, NULL,
|
||||
hgpk_trigger_recal_show, hgpk_trigger_recal, false);
|
||||
|
||||
static void hgpk_disconnect(struct psmouse *psmouse)
|
||||
{
|
||||
|
@ -375,6 +404,11 @@ static void hgpk_disconnect(struct psmouse *psmouse)
|
|||
|
||||
device_remove_file(&psmouse->ps2dev.serio->dev,
|
||||
&psmouse_attr_powered.dattr);
|
||||
|
||||
if (psmouse->model >= HGPK_MODEL_C)
|
||||
device_remove_file(&psmouse->ps2dev.serio->dev,
|
||||
&psmouse_attr_recalibrate.dattr);
|
||||
|
||||
psmouse_reset(psmouse);
|
||||
kfree(priv);
|
||||
}
|
||||
|
@ -423,10 +457,25 @@ static int hgpk_register(struct psmouse *psmouse)
|
|||
|
||||
err = device_create_file(&psmouse->ps2dev.serio->dev,
|
||||
&psmouse_attr_powered.dattr);
|
||||
if (err)
|
||||
hgpk_err(psmouse, "Failed to create sysfs attribute\n");
|
||||
if (err) {
|
||||
hgpk_err(psmouse, "Failed creating 'powered' sysfs node\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
return err;
|
||||
/* C-series touchpads added the recalibrate command */
|
||||
if (psmouse->model >= HGPK_MODEL_C) {
|
||||
err = device_create_file(&psmouse->ps2dev.serio->dev,
|
||||
&psmouse_attr_recalibrate.dattr);
|
||||
if (err) {
|
||||
hgpk_err(psmouse,
|
||||
"Failed creating 'recalibrate' sysfs node\n");
|
||||
device_remove_file(&psmouse->ps2dev.serio->dev,
|
||||
&psmouse_attr_powered.dattr);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hgpk_init(struct psmouse *psmouse)
|
||||
|
@ -440,7 +489,7 @@ int hgpk_init(struct psmouse *psmouse)
|
|||
|
||||
psmouse->private = priv;
|
||||
priv->psmouse = psmouse;
|
||||
priv->powered = 1;
|
||||
priv->powered = true;
|
||||
INIT_DELAYED_WORK(&priv->recalib_wq, hgpk_recalib_work);
|
||||
|
||||
err = psmouse_reset(psmouse);
|
||||
|
@ -483,7 +532,7 @@ static enum hgpk_model_t hgpk_get_model(struct psmouse *psmouse)
|
|||
return param[2];
|
||||
}
|
||||
|
||||
int hgpk_detect(struct psmouse *psmouse, int set_properties)
|
||||
int hgpk_detect(struct psmouse *psmouse, bool set_properties)
|
||||
{
|
||||
int version;
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ enum hgpk_model_t {
|
|||
|
||||
struct hgpk_data {
|
||||
struct psmouse *psmouse;
|
||||
int powered;
|
||||
bool powered;
|
||||
int count, x_tally, y_tally; /* hardware workaround stuff */
|
||||
unsigned long recalib_window;
|
||||
struct delayed_work recalib_wq;
|
||||
|
@ -33,10 +33,10 @@ struct hgpk_data {
|
|||
dev_notice(&(psmouse)->ps2dev.serio->dev, format, ## arg)
|
||||
|
||||
#ifdef CONFIG_MOUSE_PS2_OLPC
|
||||
int hgpk_detect(struct psmouse *psmouse, int set_properties);
|
||||
int hgpk_detect(struct psmouse *psmouse, bool set_properties);
|
||||
int hgpk_init(struct psmouse *psmouse);
|
||||
#else
|
||||
static inline int hgpk_detect(struct psmouse *psmouse, int set_properties)
|
||||
static inline int hgpk_detect(struct psmouse *psmouse, bool set_properties)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
|
|
|
@ -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);
|
|
@ -33,11 +33,11 @@ static int lifebook_set_serio_phys(const struct dmi_system_id *d)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static unsigned char lifebook_use_6byte_proto;
|
||||
static bool lifebook_use_6byte_proto;
|
||||
|
||||
static int lifebook_set_6byte_proto(const struct dmi_system_id *d)
|
||||
{
|
||||
lifebook_use_6byte_proto = 1;
|
||||
lifebook_use_6byte_proto = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -125,7 +125,7 @@ static psmouse_ret_t lifebook_process_byte(struct psmouse *psmouse)
|
|||
struct input_dev *dev1 = psmouse->dev;
|
||||
struct input_dev *dev2 = priv ? priv->dev2 : NULL;
|
||||
unsigned char *packet = psmouse->packet;
|
||||
int relative_packet = packet[0] & 0x08;
|
||||
bool relative_packet = packet[0] & 0x08;
|
||||
|
||||
if (relative_packet || !lifebook_use_6byte_proto) {
|
||||
if (psmouse->pktcnt != 3)
|
||||
|
@ -242,7 +242,7 @@ static void lifebook_disconnect(struct psmouse *psmouse)
|
|||
psmouse->private = NULL;
|
||||
}
|
||||
|
||||
int lifebook_detect(struct psmouse *psmouse, int set_properties)
|
||||
int lifebook_detect(struct psmouse *psmouse, bool set_properties)
|
||||
{
|
||||
if (!dmi_check_system(lifebook_dmi_table))
|
||||
return -1;
|
||||
|
|
|
@ -12,10 +12,10 @@
|
|||
#define _LIFEBOOK_H
|
||||
|
||||
#ifdef CONFIG_MOUSE_PS2_LIFEBOOK
|
||||
int lifebook_detect(struct psmouse *psmouse, int set_properties);
|
||||
int lifebook_detect(struct psmouse *psmouse, bool set_properties);
|
||||
int lifebook_init(struct psmouse *psmouse);
|
||||
#else
|
||||
inline int lifebook_detect(struct psmouse *psmouse, int set_properties)
|
||||
inline int lifebook_detect(struct psmouse *psmouse, bool set_properties)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
|
|
@ -130,14 +130,11 @@ static int ps2pp_cmd(struct psmouse *psmouse, unsigned char *param, unsigned cha
|
|||
* 0 - disabled
|
||||
*/
|
||||
|
||||
static void ps2pp_set_smartscroll(struct psmouse *psmouse, unsigned int smartscroll)
|
||||
static void ps2pp_set_smartscroll(struct psmouse *psmouse, bool smartscroll)
|
||||
{
|
||||
struct ps2dev *ps2dev = &psmouse->ps2dev;
|
||||
unsigned char param[4];
|
||||
|
||||
if (smartscroll > 1)
|
||||
smartscroll = 1;
|
||||
|
||||
ps2pp_cmd(psmouse, param, 0x32);
|
||||
|
||||
param[0] = 0;
|
||||
|
@ -149,12 +146,14 @@ static void ps2pp_set_smartscroll(struct psmouse *psmouse, unsigned int smartscr
|
|||
ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
|
||||
}
|
||||
|
||||
static ssize_t ps2pp_attr_show_smartscroll(struct psmouse *psmouse, void *data, char *buf)
|
||||
static ssize_t ps2pp_attr_show_smartscroll(struct psmouse *psmouse,
|
||||
void *data, char *buf)
|
||||
{
|
||||
return sprintf(buf, "%d\n", psmouse->smartscroll ? 1 : 0);
|
||||
return sprintf(buf, "%d\n", psmouse->smartscroll);
|
||||
}
|
||||
|
||||
static ssize_t ps2pp_attr_set_smartscroll(struct psmouse *psmouse, void *data, const char *buf, size_t count)
|
||||
static ssize_t ps2pp_attr_set_smartscroll(struct psmouse *psmouse, void *data,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
unsigned long value;
|
||||
|
||||
|
@ -261,29 +260,29 @@ static const struct ps2pp_info *get_model_info(unsigned char model)
|
|||
|
||||
static void ps2pp_set_model_properties(struct psmouse *psmouse,
|
||||
const struct ps2pp_info *model_info,
|
||||
int using_ps2pp)
|
||||
bool using_ps2pp)
|
||||
{
|
||||
struct input_dev *input_dev = psmouse->dev;
|
||||
|
||||
if (model_info->features & PS2PP_SIDE_BTN)
|
||||
set_bit(BTN_SIDE, input_dev->keybit);
|
||||
__set_bit(BTN_SIDE, input_dev->keybit);
|
||||
|
||||
if (model_info->features & PS2PP_EXTRA_BTN)
|
||||
set_bit(BTN_EXTRA, input_dev->keybit);
|
||||
__set_bit(BTN_EXTRA, input_dev->keybit);
|
||||
|
||||
if (model_info->features & PS2PP_TASK_BTN)
|
||||
set_bit(BTN_TASK, input_dev->keybit);
|
||||
__set_bit(BTN_TASK, input_dev->keybit);
|
||||
|
||||
if (model_info->features & PS2PP_NAV_BTN) {
|
||||
set_bit(BTN_FORWARD, input_dev->keybit);
|
||||
set_bit(BTN_BACK, input_dev->keybit);
|
||||
__set_bit(BTN_FORWARD, input_dev->keybit);
|
||||
__set_bit(BTN_BACK, input_dev->keybit);
|
||||
}
|
||||
|
||||
if (model_info->features & PS2PP_WHEEL)
|
||||
set_bit(REL_WHEEL, input_dev->relbit);
|
||||
__set_bit(REL_WHEEL, input_dev->relbit);
|
||||
|
||||
if (model_info->features & PS2PP_HWHEEL)
|
||||
set_bit(REL_HWHEEL, input_dev->relbit);
|
||||
__set_bit(REL_HWHEEL, input_dev->relbit);
|
||||
|
||||
switch (model_info->kind) {
|
||||
case PS2PP_KIND_WHEEL:
|
||||
|
@ -321,13 +320,13 @@ static void ps2pp_set_model_properties(struct psmouse *psmouse,
|
|||
* that support it.
|
||||
*/
|
||||
|
||||
int ps2pp_init(struct psmouse *psmouse, int set_properties)
|
||||
int ps2pp_init(struct psmouse *psmouse, bool set_properties)
|
||||
{
|
||||
struct ps2dev *ps2dev = &psmouse->ps2dev;
|
||||
unsigned char param[4];
|
||||
unsigned char model, buttons;
|
||||
const struct ps2pp_info *model_info;
|
||||
int use_ps2pp = 0;
|
||||
bool use_ps2pp = false;
|
||||
int error;
|
||||
|
||||
param[0] = 0;
|
||||
|
@ -364,7 +363,7 @@ int ps2pp_init(struct psmouse *psmouse, int set_properties)
|
|||
param[0] = 0;
|
||||
if (!ps2_command(ps2dev, param, 0x13d1) &&
|
||||
param[0] == 0x06 && param[1] == 0x00 && param[2] == 0x14) {
|
||||
use_ps2pp = 1;
|
||||
use_ps2pp = true;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
@ -376,8 +375,8 @@ int ps2pp_init(struct psmouse *psmouse, int set_properties)
|
|||
if ((param[0] & 0x78) == 0x48 &&
|
||||
(param[1] & 0xf3) == 0xc2 &&
|
||||
(param[2] & 0x03) == ((param[1] >> 2) & 3)) {
|
||||
ps2pp_set_smartscroll(psmouse, psmouse->smartscroll);
|
||||
use_ps2pp = 1;
|
||||
ps2pp_set_smartscroll(psmouse, false);
|
||||
use_ps2pp = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -406,7 +405,7 @@ int ps2pp_init(struct psmouse *psmouse, int set_properties)
|
|||
}
|
||||
|
||||
if (buttons < 3)
|
||||
clear_bit(BTN_MIDDLE, psmouse->dev->keybit);
|
||||
__clear_bit(BTN_MIDDLE, psmouse->dev->keybit);
|
||||
|
||||
if (model_info)
|
||||
ps2pp_set_model_properties(psmouse, model_info, use_ps2pp);
|
||||
|
|
|
@ -12,9 +12,9 @@
|
|||
#define _LOGIPS2PP_H
|
||||
|
||||
#ifdef CONFIG_MOUSE_PS2_LOGIPS2PP
|
||||
int ps2pp_init(struct psmouse *psmouse, int set_properties);
|
||||
int ps2pp_init(struct psmouse *psmouse, bool set_properties);
|
||||
#else
|
||||
inline int ps2pp_init(struct psmouse *psmouse, int set_properties)
|
||||
inline int ps2pp_init(struct psmouse *psmouse, bool set_properties)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include "trackpoint.h"
|
||||
#include "touchkit_ps2.h"
|
||||
#include "elantech.h"
|
||||
#include "sentelic.h"
|
||||
|
||||
#define DRIVER_DESC "PS/2 mouse driver"
|
||||
|
||||
|
@ -108,10 +109,10 @@ static struct workqueue_struct *kpsmoused_wq;
|
|||
|
||||
struct psmouse_protocol {
|
||||
enum psmouse_type type;
|
||||
bool maxproto;
|
||||
const char *name;
|
||||
const char *alias;
|
||||
int maxproto;
|
||||
int (*detect)(struct psmouse *, int);
|
||||
int (*detect)(struct psmouse *, bool);
|
||||
int (*init)(struct psmouse *);
|
||||
};
|
||||
|
||||
|
@ -216,7 +217,7 @@ void psmouse_queue_work(struct psmouse *psmouse, struct delayed_work *work,
|
|||
static inline void __psmouse_set_state(struct psmouse *psmouse, enum psmouse_state new_state)
|
||||
{
|
||||
psmouse->state = new_state;
|
||||
psmouse->pktcnt = psmouse->out_of_sync = 0;
|
||||
psmouse->pktcnt = psmouse->out_of_sync_cnt = 0;
|
||||
psmouse->ps2dev.flags = 0;
|
||||
psmouse->last = jiffies;
|
||||
}
|
||||
|
@ -249,7 +250,7 @@ static int psmouse_handle_byte(struct psmouse *psmouse)
|
|||
if (psmouse->state == PSMOUSE_ACTIVATED) {
|
||||
printk(KERN_WARNING "psmouse.c: %s at %s lost sync at byte %d\n",
|
||||
psmouse->name, psmouse->phys, psmouse->pktcnt);
|
||||
if (++psmouse->out_of_sync == psmouse->resetafter) {
|
||||
if (++psmouse->out_of_sync_cnt == psmouse->resetafter) {
|
||||
__psmouse_set_state(psmouse, PSMOUSE_IGNORE);
|
||||
printk(KERN_NOTICE "psmouse.c: issuing reconnect request\n");
|
||||
serio_reconnect(psmouse->ps2dev.serio);
|
||||
|
@ -261,8 +262,8 @@ static int psmouse_handle_byte(struct psmouse *psmouse)
|
|||
|
||||
case PSMOUSE_FULL_PACKET:
|
||||
psmouse->pktcnt = 0;
|
||||
if (psmouse->out_of_sync) {
|
||||
psmouse->out_of_sync = 0;
|
||||
if (psmouse->out_of_sync_cnt) {
|
||||
psmouse->out_of_sync_cnt = 0;
|
||||
printk(KERN_NOTICE "psmouse.c: %s at %s - driver resynched.\n",
|
||||
psmouse->name, psmouse->phys);
|
||||
}
|
||||
|
@ -408,7 +409,7 @@ int psmouse_reset(struct psmouse *psmouse)
|
|||
/*
|
||||
* Genius NetMouse magic init.
|
||||
*/
|
||||
static int genius_detect(struct psmouse *psmouse, int set_properties)
|
||||
static int genius_detect(struct psmouse *psmouse, bool set_properties)
|
||||
{
|
||||
struct ps2dev *ps2dev = &psmouse->ps2dev;
|
||||
unsigned char param[4];
|
||||
|
@ -424,9 +425,9 @@ static int genius_detect(struct psmouse *psmouse, int set_properties)
|
|||
return -1;
|
||||
|
||||
if (set_properties) {
|
||||
set_bit(BTN_EXTRA, psmouse->dev->keybit);
|
||||
set_bit(BTN_SIDE, psmouse->dev->keybit);
|
||||
set_bit(REL_WHEEL, psmouse->dev->relbit);
|
||||
__set_bit(BTN_EXTRA, psmouse->dev->keybit);
|
||||
__set_bit(BTN_SIDE, psmouse->dev->keybit);
|
||||
__set_bit(REL_WHEEL, psmouse->dev->relbit);
|
||||
|
||||
psmouse->vendor = "Genius";
|
||||
psmouse->name = "Mouse";
|
||||
|
@ -439,7 +440,7 @@ static int genius_detect(struct psmouse *psmouse, int set_properties)
|
|||
/*
|
||||
* IntelliMouse magic init.
|
||||
*/
|
||||
static int intellimouse_detect(struct psmouse *psmouse, int set_properties)
|
||||
static int intellimouse_detect(struct psmouse *psmouse, bool set_properties)
|
||||
{
|
||||
struct ps2dev *ps2dev = &psmouse->ps2dev;
|
||||
unsigned char param[2];
|
||||
|
@ -456,8 +457,8 @@ static int intellimouse_detect(struct psmouse *psmouse, int set_properties)
|
|||
return -1;
|
||||
|
||||
if (set_properties) {
|
||||
set_bit(BTN_MIDDLE, psmouse->dev->keybit);
|
||||
set_bit(REL_WHEEL, psmouse->dev->relbit);
|
||||
__set_bit(BTN_MIDDLE, psmouse->dev->keybit);
|
||||
__set_bit(REL_WHEEL, psmouse->dev->relbit);
|
||||
|
||||
if (!psmouse->vendor) psmouse->vendor = "Generic";
|
||||
if (!psmouse->name) psmouse->name = "Wheel Mouse";
|
||||
|
@ -470,7 +471,7 @@ static int intellimouse_detect(struct psmouse *psmouse, int set_properties)
|
|||
/*
|
||||
* Try IntelliMouse/Explorer magic init.
|
||||
*/
|
||||
static int im_explorer_detect(struct psmouse *psmouse, int set_properties)
|
||||
static int im_explorer_detect(struct psmouse *psmouse, bool set_properties)
|
||||
{
|
||||
struct ps2dev *ps2dev = &psmouse->ps2dev;
|
||||
unsigned char param[2];
|
||||
|
@ -497,11 +498,11 @@ static int im_explorer_detect(struct psmouse *psmouse, int set_properties)
|
|||
ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
|
||||
|
||||
if (set_properties) {
|
||||
set_bit(BTN_MIDDLE, psmouse->dev->keybit);
|
||||
set_bit(REL_WHEEL, psmouse->dev->relbit);
|
||||
set_bit(REL_HWHEEL, psmouse->dev->relbit);
|
||||
set_bit(BTN_SIDE, psmouse->dev->keybit);
|
||||
set_bit(BTN_EXTRA, psmouse->dev->keybit);
|
||||
__set_bit(BTN_MIDDLE, psmouse->dev->keybit);
|
||||
__set_bit(REL_WHEEL, psmouse->dev->relbit);
|
||||
__set_bit(REL_HWHEEL, psmouse->dev->relbit);
|
||||
__set_bit(BTN_SIDE, psmouse->dev->keybit);
|
||||
__set_bit(BTN_EXTRA, psmouse->dev->keybit);
|
||||
|
||||
if (!psmouse->vendor) psmouse->vendor = "Generic";
|
||||
if (!psmouse->name) psmouse->name = "Explorer Mouse";
|
||||
|
@ -514,7 +515,7 @@ static int im_explorer_detect(struct psmouse *psmouse, int set_properties)
|
|||
/*
|
||||
* Kensington ThinkingMouse / ExpertMouse magic init.
|
||||
*/
|
||||
static int thinking_detect(struct psmouse *psmouse, int set_properties)
|
||||
static int thinking_detect(struct psmouse *psmouse, bool set_properties)
|
||||
{
|
||||
struct ps2dev *ps2dev = &psmouse->ps2dev;
|
||||
unsigned char param[2];
|
||||
|
@ -535,7 +536,7 @@ static int thinking_detect(struct psmouse *psmouse, int set_properties)
|
|||
return -1;
|
||||
|
||||
if (set_properties) {
|
||||
set_bit(BTN_EXTRA, psmouse->dev->keybit);
|
||||
__set_bit(BTN_EXTRA, psmouse->dev->keybit);
|
||||
|
||||
psmouse->vendor = "Kensington";
|
||||
psmouse->name = "ThinkingMouse";
|
||||
|
@ -547,7 +548,7 @@ static int thinking_detect(struct psmouse *psmouse, int set_properties)
|
|||
/*
|
||||
* Bare PS/2 protocol "detection". Always succeeds.
|
||||
*/
|
||||
static int ps2bare_detect(struct psmouse *psmouse, int set_properties)
|
||||
static int ps2bare_detect(struct psmouse *psmouse, bool set_properties)
|
||||
{
|
||||
if (set_properties) {
|
||||
if (!psmouse->vendor) psmouse->vendor = "Generic";
|
||||
|
@ -561,12 +562,12 @@ static int ps2bare_detect(struct psmouse *psmouse, int set_properties)
|
|||
* Cortron PS/2 protocol detection. There's no special way to detect it, so it
|
||||
* must be forced by sysfs protocol writing.
|
||||
*/
|
||||
static int cortron_detect(struct psmouse *psmouse, int set_properties)
|
||||
static int cortron_detect(struct psmouse *psmouse, bool set_properties)
|
||||
{
|
||||
if (set_properties) {
|
||||
psmouse->vendor = "Cortron";
|
||||
psmouse->name = "PS/2 Trackball";
|
||||
set_bit(BTN_SIDE, psmouse->dev->keybit);
|
||||
__set_bit(BTN_SIDE, psmouse->dev->keybit);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -578,9 +579,9 @@ static int cortron_detect(struct psmouse *psmouse, int set_properties)
|
|||
*/
|
||||
|
||||
static int psmouse_extensions(struct psmouse *psmouse,
|
||||
unsigned int max_proto, int set_properties)
|
||||
unsigned int max_proto, bool set_properties)
|
||||
{
|
||||
int synaptics_hardware = 0;
|
||||
bool synaptics_hardware = true;
|
||||
|
||||
/*
|
||||
* We always check for lifebook because it does not disturb mouse
|
||||
|
@ -607,7 +608,7 @@ static int psmouse_extensions(struct psmouse *psmouse,
|
|||
* can reset it properly after probing for intellimouse.
|
||||
*/
|
||||
if (max_proto > PSMOUSE_PS2 && synaptics_detect(psmouse, set_properties) == 0) {
|
||||
synaptics_hardware = 1;
|
||||
synaptics_hardware = true;
|
||||
|
||||
if (max_proto > PSMOUSE_IMEX) {
|
||||
if (!set_properties || synaptics_init(psmouse) == 0)
|
||||
|
@ -666,6 +667,20 @@ static int psmouse_extensions(struct psmouse *psmouse,
|
|||
max_proto = PSMOUSE_IMEX;
|
||||
}
|
||||
|
||||
/*
|
||||
* Try Finger Sensing Pad
|
||||
*/
|
||||
if (max_proto > PSMOUSE_IMEX) {
|
||||
if (fsp_detect(psmouse, set_properties) == 0) {
|
||||
if (!set_properties || fsp_init(psmouse) == 0)
|
||||
return PSMOUSE_FSP;
|
||||
/*
|
||||
* Init failed, try basic relative protocols
|
||||
*/
|
||||
max_proto = PSMOUSE_IMEX;
|
||||
}
|
||||
}
|
||||
|
||||
if (max_proto > PSMOUSE_IMEX) {
|
||||
if (genius_detect(psmouse, set_properties) == 0)
|
||||
return PSMOUSE_GENPS;
|
||||
|
@ -718,7 +733,7 @@ static const struct psmouse_protocol psmouse_protocols[] = {
|
|||
.type = PSMOUSE_PS2,
|
||||
.name = "PS/2",
|
||||
.alias = "bare",
|
||||
.maxproto = 1,
|
||||
.maxproto = true,
|
||||
.detect = ps2bare_detect,
|
||||
},
|
||||
#ifdef CONFIG_MOUSE_PS2_LOGIPS2PP
|
||||
|
@ -745,14 +760,14 @@ static const struct psmouse_protocol psmouse_protocols[] = {
|
|||
.type = PSMOUSE_IMPS,
|
||||
.name = "ImPS/2",
|
||||
.alias = "imps",
|
||||
.maxproto = 1,
|
||||
.maxproto = true,
|
||||
.detect = intellimouse_detect,
|
||||
},
|
||||
{
|
||||
.type = PSMOUSE_IMEX,
|
||||
.name = "ImExPS/2",
|
||||
.alias = "exps",
|
||||
.maxproto = 1,
|
||||
.maxproto = true,
|
||||
.detect = im_explorer_detect,
|
||||
},
|
||||
#ifdef CONFIG_MOUSE_PS2_SYNAPTICS
|
||||
|
@ -813,7 +828,16 @@ static const struct psmouse_protocol psmouse_protocols[] = {
|
|||
.detect = elantech_detect,
|
||||
.init = elantech_init,
|
||||
},
|
||||
#endif
|
||||
#endif
|
||||
#ifdef CONFIG_MOUSE_PS2_SENTELIC
|
||||
{
|
||||
.type = PSMOUSE_FSP,
|
||||
.name = "FSPPS/2",
|
||||
.alias = "fsp",
|
||||
.detect = fsp_detect,
|
||||
.init = fsp_init,
|
||||
},
|
||||
#endif
|
||||
{
|
||||
.type = PSMOUSE_CORTRON,
|
||||
.name = "CortronPS/2",
|
||||
|
@ -824,7 +848,7 @@ static const struct psmouse_protocol psmouse_protocols[] = {
|
|||
.type = PSMOUSE_AUTO,
|
||||
.name = "auto",
|
||||
.alias = "any",
|
||||
.maxproto = 1,
|
||||
.maxproto = true,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -990,7 +1014,7 @@ static void psmouse_resync(struct work_struct *work)
|
|||
container_of(work, struct psmouse, resync_work.work);
|
||||
struct serio *serio = psmouse->ps2dev.serio;
|
||||
psmouse_ret_t rc = PSMOUSE_GOOD_DATA;
|
||||
int failed = 0, enabled = 0;
|
||||
bool failed = false, enabled = false;
|
||||
int i;
|
||||
|
||||
mutex_lock(&psmouse_mutex);
|
||||
|
@ -1017,9 +1041,9 @@ static void psmouse_resync(struct work_struct *work)
|
|||
|
||||
if (ps2_sendbyte(&psmouse->ps2dev, PSMOUSE_CMD_DISABLE, 20)) {
|
||||
if (psmouse->num_resyncs < 3 || psmouse->acks_disable_command)
|
||||
failed = 1;
|
||||
failed = true;
|
||||
} else
|
||||
psmouse->acks_disable_command = 1;
|
||||
psmouse->acks_disable_command = true;
|
||||
|
||||
/*
|
||||
* Poll the mouse. If it was reset the packet will be shorter than
|
||||
|
@ -1030,7 +1054,7 @@ static void psmouse_resync(struct work_struct *work)
|
|||
*/
|
||||
if (!failed) {
|
||||
if (psmouse->poll(psmouse))
|
||||
failed = 1;
|
||||
failed = true;
|
||||
else {
|
||||
psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
|
||||
for (i = 0; i < psmouse->pktsize; i++) {
|
||||
|
@ -1040,7 +1064,7 @@ static void psmouse_resync(struct work_struct *work)
|
|||
break;
|
||||
}
|
||||
if (rc != PSMOUSE_FULL_PACKET)
|
||||
failed = 1;
|
||||
failed = true;
|
||||
psmouse_set_state(psmouse, PSMOUSE_RESYNCING);
|
||||
}
|
||||
}
|
||||
|
@ -1051,7 +1075,7 @@ static void psmouse_resync(struct work_struct *work)
|
|||
*/
|
||||
for (i = 0; i < 5; i++) {
|
||||
if (!ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_ENABLE)) {
|
||||
enabled = 1;
|
||||
enabled = true;
|
||||
break;
|
||||
}
|
||||
msleep(200);
|
||||
|
@ -1060,7 +1084,7 @@ static void psmouse_resync(struct work_struct *work)
|
|||
if (!enabled) {
|
||||
printk(KERN_WARNING "psmouse.c: failed to re-enable mouse on %s\n",
|
||||
psmouse->ps2dev.serio->phys);
|
||||
failed = 1;
|
||||
failed = true;
|
||||
}
|
||||
|
||||
if (failed) {
|
||||
|
@ -1187,7 +1211,8 @@ static int psmouse_switch_protocol(struct psmouse *psmouse, const struct psmouse
|
|||
psmouse->type = proto->type;
|
||||
}
|
||||
else
|
||||
psmouse->type = psmouse_extensions(psmouse, psmouse_max_proto, 1);
|
||||
psmouse->type = psmouse_extensions(psmouse,
|
||||
psmouse_max_proto, true);
|
||||
|
||||
/*
|
||||
* If mouse's packet size is 3 there is no point in polling the
|
||||
|
@ -1342,8 +1367,10 @@ static int psmouse_reconnect(struct serio *serio)
|
|||
if (psmouse->reconnect(psmouse))
|
||||
goto out;
|
||||
} else if (psmouse_probe(psmouse) < 0 ||
|
||||
psmouse->type != psmouse_extensions(psmouse, psmouse_max_proto, 0))
|
||||
psmouse->type != psmouse_extensions(psmouse,
|
||||
psmouse_max_proto, false)) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* ok, the device type (and capabilities) match the old one,
|
||||
* we can continue using it, complete intialization
|
||||
|
@ -1528,7 +1555,9 @@ static ssize_t psmouse_attr_set_protocol(struct psmouse *psmouse, void *data, co
|
|||
|
||||
while (serio->child) {
|
||||
if (++retry > 3) {
|
||||
printk(KERN_WARNING "psmouse: failed to destroy child port, protocol change aborted.\n");
|
||||
printk(KERN_WARNING
|
||||
"psmouse: failed to destroy child port, "
|
||||
"protocol change aborted.\n");
|
||||
input_free_device(new_dev);
|
||||
return -EIO;
|
||||
}
|
||||
|
|
|
@ -47,10 +47,10 @@ struct psmouse {
|
|||
unsigned char pktcnt;
|
||||
unsigned char pktsize;
|
||||
unsigned char type;
|
||||
unsigned char acks_disable_command;
|
||||
bool acks_disable_command;
|
||||
unsigned int model;
|
||||
unsigned long last;
|
||||
unsigned long out_of_sync;
|
||||
unsigned long out_of_sync_cnt;
|
||||
unsigned long num_resyncs;
|
||||
enum psmouse_state state;
|
||||
char devname[64];
|
||||
|
@ -60,7 +60,7 @@ struct psmouse {
|
|||
unsigned int resolution;
|
||||
unsigned int resetafter;
|
||||
unsigned int resync_time;
|
||||
unsigned int smartscroll; /* Logitech only */
|
||||
bool smartscroll; /* Logitech only */
|
||||
|
||||
psmouse_ret_t (*protocol_handler)(struct psmouse *psmouse);
|
||||
void (*set_rate)(struct psmouse *psmouse, unsigned int rate);
|
||||
|
@ -91,6 +91,7 @@ enum psmouse_type {
|
|||
PSMOUSE_CORTRON,
|
||||
PSMOUSE_HGPK,
|
||||
PSMOUSE_ELANTECH,
|
||||
PSMOUSE_FSP,
|
||||
PSMOUSE_AUTO /* This one should always be last */
|
||||
};
|
||||
|
||||
|
@ -107,7 +108,7 @@ struct psmouse_attribute {
|
|||
ssize_t (*show)(struct psmouse *psmouse, void *data, char *buf);
|
||||
ssize_t (*set)(struct psmouse *psmouse, void *data,
|
||||
const char *buf, size_t count);
|
||||
int protect;
|
||||
bool protect;
|
||||
};
|
||||
#define to_psmouse_attr(a) container_of((a), struct psmouse_attribute, dattr)
|
||||
|
||||
|
@ -116,9 +117,7 @@ ssize_t psmouse_attr_show_helper(struct device *dev, struct device_attribute *at
|
|||
ssize_t psmouse_attr_set_helper(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count);
|
||||
|
||||
#define __PSMOUSE_DEFINE_ATTR(_name, _mode, _data, _show, _set, _protect) \
|
||||
static ssize_t _show(struct psmouse *, void *data, char *); \
|
||||
static ssize_t _set(struct psmouse *, void *data, const char *, size_t); \
|
||||
#define __PSMOUSE_DEFINE_ATTR_VAR(_name, _mode, _data, _show, _set, _protect) \
|
||||
static struct psmouse_attribute psmouse_attr_##_name = { \
|
||||
.dattr = { \
|
||||
.attr = { \
|
||||
|
@ -134,7 +133,20 @@ static struct psmouse_attribute psmouse_attr_##_name = { \
|
|||
.protect = _protect, \
|
||||
}
|
||||
|
||||
#define PSMOUSE_DEFINE_ATTR(_name, _mode, _data, _show, _set) \
|
||||
__PSMOUSE_DEFINE_ATTR(_name, _mode, _data, _show, _set, 1)
|
||||
#define __PSMOUSE_DEFINE_ATTR(_name, _mode, _data, _show, _set, _protect) \
|
||||
static ssize_t _show(struct psmouse *, void *, char *); \
|
||||
static ssize_t _set(struct psmouse *, void *, const char *, size_t); \
|
||||
__PSMOUSE_DEFINE_ATTR_VAR(_name, _mode, _data, _show, _set, _protect)
|
||||
|
||||
#define PSMOUSE_DEFINE_ATTR(_name, _mode, _data, _show, _set) \
|
||||
__PSMOUSE_DEFINE_ATTR(_name, _mode, _data, _show, _set, true)
|
||||
|
||||
#define PSMOUSE_DEFINE_RO_ATTR(_name, _mode, _data, _show) \
|
||||
static ssize_t _show(struct psmouse *, void *, char *); \
|
||||
__PSMOUSE_DEFINE_ATTR_VAR(_name, _mode, _data, _show, NULL, true)
|
||||
|
||||
#define PSMOUSE_DEFINE_WO_ATTR(_name, _mode, _data, _set) \
|
||||
static ssize_t _set(struct psmouse *, void *, const char *, size_t); \
|
||||
__PSMOUSE_DEFINE_ATTR_VAR(_name, _mode, _data, NULL, _set, true)
|
||||
|
||||
#endif /* _PSMOUSE_H */
|
||||
|
|
867
drivers/input/mouse/sentelic.c
Normal file
867
drivers/input/mouse/sentelic.c
Normal file
|
@ -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 > 0xff)
|
||||
return -EINVAL;
|
||||
|
||||
if (fsp_reg_read(psmouse, reg, &val))
|
||||
return -EIO;
|
||||
|
||||
pad->last_reg = reg;
|
||||
pad->last_val = val;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
PSMOUSE_DEFINE_ATTR(getreg, S_IWUSR | S_IRUGO, NULL,
|
||||
fsp_attr_show_getreg, fsp_attr_set_getreg);
|
||||
|
||||
static ssize_t fsp_attr_show_pagereg(struct psmouse *psmouse,
|
||||
void *data, char *buf)
|
||||
{
|
||||
int val = 0;
|
||||
|
||||
if (fsp_page_reg_read(psmouse, &val))
|
||||
return -EIO;
|
||||
|
||||
return sprintf(buf, "%02x\n", val);
|
||||
}
|
||||
|
||||
static ssize_t fsp_attr_set_pagereg(struct psmouse *psmouse, void *data,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
unsigned long val;
|
||||
|
||||
if (strict_strtoul(buf, 16, &val) || val > 0xff)
|
||||
return -EINVAL;
|
||||
|
||||
if (fsp_page_reg_write(psmouse, val))
|
||||
return -EIO;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
PSMOUSE_DEFINE_ATTR(page, S_IWUSR | S_IRUGO, NULL,
|
||||
fsp_attr_show_pagereg, fsp_attr_set_pagereg);
|
||||
|
||||
static ssize_t fsp_attr_show_vscroll(struct psmouse *psmouse,
|
||||
void *data, char *buf)
|
||||
{
|
||||
struct fsp_data *pad = psmouse->private;
|
||||
|
||||
return sprintf(buf, "%d\n", pad->vscroll);
|
||||
}
|
||||
|
||||
static ssize_t fsp_attr_set_vscroll(struct psmouse *psmouse, void *data,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
unsigned long val;
|
||||
|
||||
if (strict_strtoul(buf, 10, &val) || val > 1)
|
||||
return -EINVAL;
|
||||
|
||||
fsp_onpad_vscr(psmouse, val);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
PSMOUSE_DEFINE_ATTR(vscroll, S_IWUSR | S_IRUGO, NULL,
|
||||
fsp_attr_show_vscroll, fsp_attr_set_vscroll);
|
||||
|
||||
static ssize_t fsp_attr_show_hscroll(struct psmouse *psmouse,
|
||||
void *data, char *buf)
|
||||
{
|
||||
struct fsp_data *pad = psmouse->private;
|
||||
|
||||
return sprintf(buf, "%d\n", pad->hscroll);
|
||||
}
|
||||
|
||||
static ssize_t fsp_attr_set_hscroll(struct psmouse *psmouse, void *data,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
unsigned long val;
|
||||
|
||||
if (strict_strtoul(buf, 10, &val) || val > 1)
|
||||
return -EINVAL;
|
||||
|
||||
fsp_onpad_hscr(psmouse, val);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
PSMOUSE_DEFINE_ATTR(hscroll, S_IWUSR | S_IRUGO, NULL,
|
||||
fsp_attr_show_hscroll, fsp_attr_set_hscroll);
|
||||
|
||||
static ssize_t fsp_attr_show_flags(struct psmouse *psmouse,
|
||||
void *data, char *buf)
|
||||
{
|
||||
struct fsp_data *pad = psmouse->private;
|
||||
|
||||
return sprintf(buf, "%c\n",
|
||||
pad->flags & FSPDRV_FLAG_EN_OPC ? 'C' : 'c');
|
||||
}
|
||||
|
||||
static ssize_t fsp_attr_set_flags(struct psmouse *psmouse, void *data,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct fsp_data *pad = psmouse->private;
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
switch (buf[i]) {
|
||||
case 'C':
|
||||
pad->flags |= FSPDRV_FLAG_EN_OPC;
|
||||
break;
|
||||
case 'c':
|
||||
pad->flags &= ~FSPDRV_FLAG_EN_OPC;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
PSMOUSE_DEFINE_ATTR(flags, S_IWUSR | S_IRUGO, NULL,
|
||||
fsp_attr_show_flags, fsp_attr_set_flags);
|
||||
|
||||
static ssize_t fsp_attr_show_ver(struct psmouse *psmouse,
|
||||
void *data, char *buf)
|
||||
{
|
||||
return sprintf(buf, "Sentelic FSP kernel module %s\n", fsp_drv_ver);
|
||||
}
|
||||
|
||||
PSMOUSE_DEFINE_RO_ATTR(ver, S_IRUGO, NULL, fsp_attr_show_ver);
|
||||
|
||||
static struct attribute *fsp_attributes[] = {
|
||||
&psmouse_attr_setreg.dattr.attr,
|
||||
&psmouse_attr_getreg.dattr.attr,
|
||||
&psmouse_attr_page.dattr.attr,
|
||||
&psmouse_attr_vscroll.dattr.attr,
|
||||
&psmouse_attr_hscroll.dattr.attr,
|
||||
&psmouse_attr_flags.dattr.attr,
|
||||
&psmouse_attr_ver.dattr.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static struct attribute_group fsp_attribute_group = {
|
||||
.attrs = fsp_attributes,
|
||||
};
|
||||
|
||||
#ifdef FSP_DEBUG
|
||||
static void fsp_packet_debug(unsigned char packet[])
|
||||
{
|
||||
static unsigned int ps2_packet_cnt;
|
||||
static unsigned int ps2_last_second;
|
||||
unsigned int jiffies_msec;
|
||||
|
||||
ps2_packet_cnt++;
|
||||
jiffies_msec = jiffies_to_msecs(jiffies);
|
||||
printk(KERN_DEBUG "%08dms PS/2 packets: %02x, %02x, %02x, %02x\n",
|
||||
jiffies_msec, packet[0], packet[1], packet[2], packet[3]);
|
||||
|
||||
if (jiffies_msec - ps2_last_second > 1000) {
|
||||
printk(KERN_DEBUG "PS/2 packets/sec = %d\n", ps2_packet_cnt);
|
||||
ps2_packet_cnt = 0;
|
||||
ps2_last_second = jiffies_msec;
|
||||
}
|
||||
}
|
||||
#else
|
||||
static void fsp_packet_debug(unsigned char packet[])
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
static psmouse_ret_t fsp_process_byte(struct psmouse *psmouse)
|
||||
{
|
||||
struct input_dev *dev = psmouse->dev;
|
||||
struct fsp_data *ad = psmouse->private;
|
||||
unsigned char *packet = psmouse->packet;
|
||||
unsigned char button_status = 0, lscroll = 0, rscroll = 0;
|
||||
int rel_x, rel_y;
|
||||
|
||||
if (psmouse->pktcnt < 4)
|
||||
return PSMOUSE_GOOD_DATA;
|
||||
|
||||
/*
|
||||
* Full packet accumulated, process it
|
||||
*/
|
||||
|
||||
switch (psmouse->packet[0] >> FSP_PKT_TYPE_SHIFT) {
|
||||
case FSP_PKT_TYPE_ABS:
|
||||
dev_warn(&psmouse->ps2dev.serio->dev,
|
||||
"Unexpected absolute mode packet, ignored.\n");
|
||||
break;
|
||||
|
||||
case FSP_PKT_TYPE_NORMAL_OPC:
|
||||
/* on-pad click, filter it if necessary */
|
||||
if ((ad->flags & FSPDRV_FLAG_EN_OPC) != FSPDRV_FLAG_EN_OPC)
|
||||
packet[0] &= ~BIT(0);
|
||||
/* fall through */
|
||||
|
||||
case FSP_PKT_TYPE_NORMAL:
|
||||
/* normal packet */
|
||||
/* special packet data translation from on-pad packets */
|
||||
if (packet[3] != 0) {
|
||||
if (packet[3] & BIT(0))
|
||||
button_status |= 0x01; /* wheel down */
|
||||
if (packet[3] & BIT(1))
|
||||
button_status |= 0x0f; /* wheel up */
|
||||
if (packet[3] & BIT(2))
|
||||
button_status |= BIT(5);/* horizontal left */
|
||||
if (packet[3] & BIT(3))
|
||||
button_status |= BIT(4);/* horizontal right */
|
||||
/* push back to packet queue */
|
||||
if (button_status != 0)
|
||||
packet[3] = button_status;
|
||||
rscroll = (packet[3] >> 4) & 1;
|
||||
lscroll = (packet[3] >> 5) & 1;
|
||||
}
|
||||
/*
|
||||
* Processing wheel up/down and extra button events
|
||||
*/
|
||||
input_report_rel(dev, REL_WHEEL,
|
||||
(int)(packet[3] & 8) - (int)(packet[3] & 7));
|
||||
input_report_rel(dev, REL_HWHEEL, lscroll - rscroll);
|
||||
input_report_key(dev, BTN_BACK, lscroll);
|
||||
input_report_key(dev, BTN_FORWARD, rscroll);
|
||||
|
||||
/*
|
||||
* Standard PS/2 Mouse
|
||||
*/
|
||||
input_report_key(dev, BTN_LEFT, packet[0] & 1);
|
||||
input_report_key(dev, BTN_MIDDLE, (packet[0] >> 2) & 1);
|
||||
input_report_key(dev, BTN_RIGHT, (packet[0] >> 1) & 1);
|
||||
|
||||
rel_x = packet[1] ? (int)packet[1] - (int)((packet[0] << 4) & 0x100) : 0;
|
||||
rel_y = packet[2] ? (int)((packet[0] << 3) & 0x100) - (int)packet[2] : 0;
|
||||
|
||||
input_report_rel(dev, REL_X, rel_x);
|
||||
input_report_rel(dev, REL_Y, rel_y);
|
||||
break;
|
||||
}
|
||||
|
||||
input_sync(dev);
|
||||
|
||||
fsp_packet_debug(packet);
|
||||
|
||||
return PSMOUSE_FULL_PACKET;
|
||||
}
|
||||
|
||||
static int fsp_activate_protocol(struct psmouse *psmouse)
|
||||
{
|
||||
struct fsp_data *pad = psmouse->private;
|
||||
struct ps2dev *ps2dev = &psmouse->ps2dev;
|
||||
unsigned char param[2];
|
||||
int val;
|
||||
|
||||
/*
|
||||
* Standard procedure to enter FSP Intellimouse mode
|
||||
* (scrolling wheel, 4th and 5th buttons)
|
||||
*/
|
||||
param[0] = 200;
|
||||
ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
|
||||
param[0] = 200;
|
||||
ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
|
||||
param[0] = 80;
|
||||
ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
|
||||
|
||||
ps2_command(ps2dev, param, PSMOUSE_CMD_GETID);
|
||||
if (param[0] != 0x04) {
|
||||
dev_err(&psmouse->ps2dev.serio->dev,
|
||||
"Unable to enable 4 bytes packet format.\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (fsp_reg_read(psmouse, FSP_REG_SYSCTL5, &val)) {
|
||||
dev_err(&psmouse->ps2dev.serio->dev,
|
||||
"Unable to read SYSCTL5 register.\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
val &= ~(FSP_BIT_EN_MSID7 | FSP_BIT_EN_MSID8 | FSP_BIT_EN_AUTO_MSID8);
|
||||
/* Ensure we are not in absolute mode */
|
||||
val &= ~FSP_BIT_EN_PKT_G0;
|
||||
if (pad->buttons == 0x06) {
|
||||
/* Left/Middle/Right & Scroll Up/Down/Right/Left */
|
||||
val |= FSP_BIT_EN_MSID6;
|
||||
}
|
||||
|
||||
if (fsp_reg_write(psmouse, FSP_REG_SYSCTL5, val)) {
|
||||
dev_err(&psmouse->ps2dev.serio->dev,
|
||||
"Unable to set up required mode bits.\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/*
|
||||
* Enable OPC tags such that driver can tell the difference between
|
||||
* on-pad and real button click
|
||||
*/
|
||||
if (fsp_opc_tag_enable(psmouse, true))
|
||||
dev_warn(&psmouse->ps2dev.serio->dev,
|
||||
"Failed to enable OPC tag mode.\n");
|
||||
|
||||
/* Enable on-pad vertical and horizontal scrolling */
|
||||
fsp_onpad_vscr(psmouse, true);
|
||||
fsp_onpad_hscr(psmouse, true);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fsp_detect(struct psmouse *psmouse, bool set_properties)
|
||||
{
|
||||
int id;
|
||||
|
||||
if (fsp_reg_read(psmouse, FSP_REG_DEVICE_ID, &id))
|
||||
return -EIO;
|
||||
|
||||
if (id != 0x01)
|
||||
return -ENODEV;
|
||||
|
||||
if (set_properties) {
|
||||
psmouse->vendor = "Sentelic";
|
||||
psmouse->name = "FingerSensingPad";
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void fsp_reset(struct psmouse *psmouse)
|
||||
{
|
||||
fsp_opc_tag_enable(psmouse, false);
|
||||
fsp_onpad_vscr(psmouse, false);
|
||||
fsp_onpad_hscr(psmouse, false);
|
||||
}
|
||||
|
||||
static void fsp_disconnect(struct psmouse *psmouse)
|
||||
{
|
||||
sysfs_remove_group(&psmouse->ps2dev.serio->dev.kobj,
|
||||
&fsp_attribute_group);
|
||||
|
||||
fsp_reset(psmouse);
|
||||
kfree(psmouse->private);
|
||||
}
|
||||
|
||||
static int fsp_reconnect(struct psmouse *psmouse)
|
||||
{
|
||||
int version;
|
||||
|
||||
if (fsp_detect(psmouse, 0))
|
||||
return -ENODEV;
|
||||
|
||||
if (fsp_get_version(psmouse, &version))
|
||||
return -ENODEV;
|
||||
|
||||
if (fsp_activate_protocol(psmouse))
|
||||
return -EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fsp_init(struct psmouse *psmouse)
|
||||
{
|
||||
struct fsp_data *priv;
|
||||
int ver, rev, buttons;
|
||||
int error;
|
||||
|
||||
if (fsp_get_version(psmouse, &ver) ||
|
||||
fsp_get_revision(psmouse, &rev) ||
|
||||
fsp_get_buttons(psmouse, &buttons)) {
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
printk(KERN_INFO
|
||||
"Finger Sensing Pad, hw: %d.%d.%d, sw: %s, buttons: %d\n",
|
||||
ver >> 4, ver & 0x0F, rev, fsp_drv_ver, buttons & 7);
|
||||
|
||||
psmouse->private = priv = kzalloc(sizeof(struct fsp_data), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
priv->ver = ver;
|
||||
priv->rev = rev;
|
||||
priv->buttons = buttons;
|
||||
|
||||
/* enable on-pad click by default */
|
||||
priv->flags |= FSPDRV_FLAG_EN_OPC;
|
||||
|
||||
/* Set up various supported input event bits */
|
||||
__set_bit(BTN_BACK, psmouse->dev->keybit);
|
||||
__set_bit(BTN_FORWARD, psmouse->dev->keybit);
|
||||
__set_bit(REL_WHEEL, psmouse->dev->relbit);
|
||||
__set_bit(REL_HWHEEL, psmouse->dev->relbit);
|
||||
|
||||
psmouse->protocol_handler = fsp_process_byte;
|
||||
psmouse->disconnect = fsp_disconnect;
|
||||
psmouse->reconnect = fsp_reconnect;
|
||||
psmouse->cleanup = fsp_reset;
|
||||
psmouse->pktsize = 4;
|
||||
|
||||
/* set default packet output based on number of buttons we found */
|
||||
error = fsp_activate_protocol(psmouse);
|
||||
if (error)
|
||||
goto err_out;
|
||||
|
||||
error = sysfs_create_group(&psmouse->ps2dev.serio->dev.kobj,
|
||||
&fsp_attribute_group);
|
||||
if (error) {
|
||||
dev_err(&psmouse->ps2dev.serio->dev,
|
||||
"Failed to create sysfs attributes (%d)", error);
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_out:
|
||||
kfree(psmouse->private);
|
||||
psmouse->private = NULL;
|
||||
return error;
|
||||
}
|
98
drivers/input/mouse/sentelic.h
Normal file
98
drivers/input/mouse/sentelic.h
Normal file
|
@ -0,0 +1,98 @@
|
|||
/*-
|
||||
* Finger Sensing Pad PS/2 mouse driver.
|
||||
*
|
||||
* Copyright (C) 2005-2007 Asia Vital Components Co., Ltd.
|
||||
* Copyright (C) 2005-2009 Tai-hwa Liang, Sentelic Corporation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef __SENTELIC_H
|
||||
#define __SENTELIC_H
|
||||
|
||||
/* Finger-sensing Pad information registers */
|
||||
#define FSP_REG_DEVICE_ID 0x00
|
||||
#define FSP_REG_VERSION 0x01
|
||||
#define FSP_REG_REVISION 0x04
|
||||
#define FSP_REG_TMOD_STATUS1 0x0B
|
||||
#define FSP_BIT_NO_ROTATION BIT(3)
|
||||
#define FSP_REG_PAGE_CTRL 0x0F
|
||||
|
||||
/* Finger-sensing Pad control registers */
|
||||
#define FSP_REG_SYSCTL1 0x10
|
||||
#define FSP_BIT_EN_REG_CLK BIT(5)
|
||||
#define FSP_REG_OPC_QDOWN 0x31
|
||||
#define FSP_BIT_EN_OPC_TAG BIT(7)
|
||||
#define FSP_REG_OPTZ_XLO 0x34
|
||||
#define FSP_REG_OPTZ_XHI 0x35
|
||||
#define FSP_REG_OPTZ_YLO 0x36
|
||||
#define FSP_REG_OPTZ_YHI 0x37
|
||||
#define FSP_REG_SYSCTL5 0x40
|
||||
#define FSP_BIT_90_DEGREE BIT(0)
|
||||
#define FSP_BIT_EN_MSID6 BIT(1)
|
||||
#define FSP_BIT_EN_MSID7 BIT(2)
|
||||
#define FSP_BIT_EN_MSID8 BIT(3)
|
||||
#define FSP_BIT_EN_AUTO_MSID8 BIT(5)
|
||||
#define FSP_BIT_EN_PKT_G0 BIT(6)
|
||||
|
||||
#define FSP_REG_ONPAD_CTL 0x43
|
||||
#define FSP_BIT_ONPAD_ENABLE BIT(0)
|
||||
#define FSP_BIT_ONPAD_FBBB BIT(1)
|
||||
#define FSP_BIT_FIX_VSCR BIT(3)
|
||||
#define FSP_BIT_FIX_HSCR BIT(5)
|
||||
#define FSP_BIT_DRAG_LOCK BIT(6)
|
||||
|
||||
/* Finger-sensing Pad packet formating related definitions */
|
||||
|
||||
/* absolute packet type */
|
||||
#define FSP_PKT_TYPE_NORMAL (0x00)
|
||||
#define FSP_PKT_TYPE_ABS (0x01)
|
||||
#define FSP_PKT_TYPE_NOTIFY (0x02)
|
||||
#define FSP_PKT_TYPE_NORMAL_OPC (0x03)
|
||||
#define FSP_PKT_TYPE_SHIFT (6)
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
struct fsp_data {
|
||||
unsigned char ver; /* hardware version */
|
||||
unsigned char rev; /* hardware revison */
|
||||
unsigned char buttons; /* Number of buttons */
|
||||
unsigned int flags;
|
||||
#define FSPDRV_FLAG_EN_OPC (0x001) /* enable on-pad clicking */
|
||||
|
||||
bool vscroll; /* Vertical scroll zone enabled */
|
||||
bool hscroll; /* Horizontal scroll zone enabled */
|
||||
|
||||
unsigned char last_reg; /* Last register we requested read from */
|
||||
unsigned char last_val;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_MOUSE_PS2_SENTELIC
|
||||
extern int fsp_detect(struct psmouse *psmouse, bool set_properties);
|
||||
extern int fsp_init(struct psmouse *psmouse);
|
||||
#else
|
||||
inline int fsp_detect(struct psmouse *psmouse, bool set_properties)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
inline int fsp_init(struct psmouse *psmouse)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __KERNEL__ */
|
||||
|
||||
#endif /* !__SENTELIC_H */
|
|
@ -60,7 +60,7 @@ static int synaptics_mode_cmd(struct psmouse *psmouse, unsigned char mode)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int synaptics_detect(struct psmouse *psmouse, int set_properties)
|
||||
int synaptics_detect(struct psmouse *psmouse, bool set_properties)
|
||||
{
|
||||
struct ps2dev *ps2dev = &psmouse->ps2dev;
|
||||
unsigned char param[4];
|
||||
|
@ -556,38 +556,38 @@ static void set_input_params(struct input_dev *dev, struct synaptics_data *priv)
|
|||
{
|
||||
int i;
|
||||
|
||||
set_bit(EV_ABS, dev->evbit);
|
||||
__set_bit(EV_ABS, dev->evbit);
|
||||
input_set_abs_params(dev, ABS_X, XMIN_NOMINAL, XMAX_NOMINAL, 0, 0);
|
||||
input_set_abs_params(dev, ABS_Y, YMIN_NOMINAL, YMAX_NOMINAL, 0, 0);
|
||||
input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0);
|
||||
set_bit(ABS_TOOL_WIDTH, dev->absbit);
|
||||
__set_bit(ABS_TOOL_WIDTH, dev->absbit);
|
||||
|
||||
set_bit(EV_KEY, dev->evbit);
|
||||
set_bit(BTN_TOUCH, dev->keybit);
|
||||
set_bit(BTN_TOOL_FINGER, dev->keybit);
|
||||
set_bit(BTN_LEFT, dev->keybit);
|
||||
set_bit(BTN_RIGHT, dev->keybit);
|
||||
__set_bit(EV_KEY, dev->evbit);
|
||||
__set_bit(BTN_TOUCH, dev->keybit);
|
||||
__set_bit(BTN_TOOL_FINGER, dev->keybit);
|
||||
__set_bit(BTN_LEFT, dev->keybit);
|
||||
__set_bit(BTN_RIGHT, dev->keybit);
|
||||
|
||||
if (SYN_CAP_MULTIFINGER(priv->capabilities)) {
|
||||
set_bit(BTN_TOOL_DOUBLETAP, dev->keybit);
|
||||
set_bit(BTN_TOOL_TRIPLETAP, dev->keybit);
|
||||
__set_bit(BTN_TOOL_DOUBLETAP, dev->keybit);
|
||||
__set_bit(BTN_TOOL_TRIPLETAP, dev->keybit);
|
||||
}
|
||||
|
||||
if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities))
|
||||
set_bit(BTN_MIDDLE, dev->keybit);
|
||||
__set_bit(BTN_MIDDLE, dev->keybit);
|
||||
|
||||
if (SYN_CAP_FOUR_BUTTON(priv->capabilities) ||
|
||||
SYN_CAP_MIDDLE_BUTTON(priv->capabilities)) {
|
||||
set_bit(BTN_FORWARD, dev->keybit);
|
||||
set_bit(BTN_BACK, dev->keybit);
|
||||
__set_bit(BTN_FORWARD, dev->keybit);
|
||||
__set_bit(BTN_BACK, dev->keybit);
|
||||
}
|
||||
|
||||
for (i = 0; i < SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap); i++)
|
||||
set_bit(BTN_0 + i, dev->keybit);
|
||||
__set_bit(BTN_0 + i, dev->keybit);
|
||||
|
||||
clear_bit(EV_REL, dev->evbit);
|
||||
clear_bit(REL_X, dev->relbit);
|
||||
clear_bit(REL_Y, dev->relbit);
|
||||
__clear_bit(EV_REL, dev->evbit);
|
||||
__clear_bit(REL_X, dev->relbit);
|
||||
__clear_bit(REL_Y, dev->relbit);
|
||||
|
||||
dev->absres[ABS_X] = priv->x_res;
|
||||
dev->absres[ABS_Y] = priv->y_res;
|
||||
|
|
|
@ -105,7 +105,7 @@ struct synaptics_data {
|
|||
int scroll;
|
||||
};
|
||||
|
||||
int synaptics_detect(struct psmouse *psmouse, int set_properties);
|
||||
int synaptics_detect(struct psmouse *psmouse, bool set_properties);
|
||||
int synaptics_init(struct psmouse *psmouse);
|
||||
void synaptics_reset(struct psmouse *psmouse);
|
||||
|
||||
|
|
|
@ -67,7 +67,7 @@ static psmouse_ret_t touchkit_ps2_process_byte(struct psmouse *psmouse)
|
|||
return PSMOUSE_FULL_PACKET;
|
||||
}
|
||||
|
||||
int touchkit_ps2_detect(struct psmouse *psmouse, int set_properties)
|
||||
int touchkit_ps2_detect(struct psmouse *psmouse, bool set_properties)
|
||||
{
|
||||
struct input_dev *dev = psmouse->dev;
|
||||
unsigned char param[3];
|
||||
|
@ -86,7 +86,7 @@ int touchkit_ps2_detect(struct psmouse *psmouse, int set_properties)
|
|||
|
||||
if (set_properties) {
|
||||
dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
|
||||
set_bit(BTN_TOUCH, dev->keybit);
|
||||
__set_bit(BTN_TOUCH, dev->keybit);
|
||||
input_set_abs_params(dev, ABS_X, 0, TOUCHKIT_MAX_XC, 0, 0);
|
||||
input_set_abs_params(dev, ABS_Y, 0, TOUCHKIT_MAX_YC, 0, 0);
|
||||
|
||||
|
|
|
@ -13,10 +13,10 @@
|
|||
#define _TOUCHKIT_PS2_H
|
||||
|
||||
#ifdef CONFIG_MOUSE_PS2_TOUCHKIT
|
||||
int touchkit_ps2_detect(struct psmouse *psmouse, int set_properties);
|
||||
int touchkit_ps2_detect(struct psmouse *psmouse, bool set_properties);
|
||||
#else
|
||||
static inline int touchkit_ps2_detect(struct psmouse *psmouse,
|
||||
int set_properties)
|
||||
bool set_properties)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
|
|
@ -282,7 +282,7 @@ static int trackpoint_reconnect(struct psmouse *psmouse)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int trackpoint_detect(struct psmouse *psmouse, int set_properties)
|
||||
int trackpoint_detect(struct psmouse *psmouse, bool set_properties)
|
||||
{
|
||||
struct trackpoint_data *priv;
|
||||
struct ps2dev *ps2dev = &psmouse->ps2dev;
|
||||
|
|
|
@ -143,9 +143,9 @@ struct trackpoint_data
|
|||
};
|
||||
|
||||
#ifdef CONFIG_MOUSE_PS2_TRACKPOINT
|
||||
int trackpoint_detect(struct psmouse *psmouse, int set_properties);
|
||||
int trackpoint_detect(struct psmouse *psmouse, bool set_properties);
|
||||
#else
|
||||
inline int trackpoint_detect(struct psmouse *psmouse, int set_properties)
|
||||
inline int trackpoint_detect(struct psmouse *psmouse, bool set_properties)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -457,6 +457,34 @@ static struct dmi_system_id __initdata i8042_dmi_nopnp_table[] = {
|
|||
},
|
||||
{ }
|
||||
};
|
||||
|
||||
static struct dmi_system_id __initdata i8042_dmi_laptop_table[] = {
|
||||
{
|
||||
.ident = "Portable",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_CHASSIS_TYPE, "8"), /* Portable */
|
||||
},
|
||||
},
|
||||
{
|
||||
.ident = "Laptop",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_CHASSIS_TYPE, "9"), /* Laptop */
|
||||
},
|
||||
},
|
||||
{
|
||||
.ident = "Notebook",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_CHASSIS_TYPE, "10"), /* Notebook */
|
||||
},
|
||||
},
|
||||
{
|
||||
.ident = "Sub-Notebook",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_CHASSIS_TYPE, "14"), /* Sub-Notebook */
|
||||
},
|
||||
},
|
||||
{ }
|
||||
};
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
@ -530,9 +558,9 @@ static struct dmi_system_id __initdata i8042_dmi_dritek_table[] = {
|
|||
#ifdef CONFIG_PNP
|
||||
#include <linux/pnp.h>
|
||||
|
||||
static int i8042_pnp_kbd_registered;
|
||||
static bool i8042_pnp_kbd_registered;
|
||||
static unsigned int i8042_pnp_kbd_devices;
|
||||
static int i8042_pnp_aux_registered;
|
||||
static bool i8042_pnp_aux_registered;
|
||||
static unsigned int i8042_pnp_aux_devices;
|
||||
|
||||
static int i8042_pnp_command_reg;
|
||||
|
@ -620,12 +648,12 @@ static struct pnp_driver i8042_pnp_aux_driver = {
|
|||
static void i8042_pnp_exit(void)
|
||||
{
|
||||
if (i8042_pnp_kbd_registered) {
|
||||
i8042_pnp_kbd_registered = 0;
|
||||
i8042_pnp_kbd_registered = false;
|
||||
pnp_unregister_driver(&i8042_pnp_kbd_driver);
|
||||
}
|
||||
|
||||
if (i8042_pnp_aux_registered) {
|
||||
i8042_pnp_aux_registered = 0;
|
||||
i8042_pnp_aux_registered = false;
|
||||
pnp_unregister_driver(&i8042_pnp_aux_driver);
|
||||
}
|
||||
}
|
||||
|
@ -633,12 +661,12 @@ static void i8042_pnp_exit(void)
|
|||
static int __init i8042_pnp_init(void)
|
||||
{
|
||||
char kbd_irq_str[4] = { 0 }, aux_irq_str[4] = { 0 };
|
||||
int pnp_data_busted = 0;
|
||||
int pnp_data_busted = false;
|
||||
int err;
|
||||
|
||||
#ifdef CONFIG_X86
|
||||
if (dmi_check_system(i8042_dmi_nopnp_table))
|
||||
i8042_nopnp = 1;
|
||||
i8042_nopnp = true;
|
||||
#endif
|
||||
|
||||
if (i8042_nopnp) {
|
||||
|
@ -648,11 +676,11 @@ static int __init i8042_pnp_init(void)
|
|||
|
||||
err = pnp_register_driver(&i8042_pnp_kbd_driver);
|
||||
if (!err)
|
||||
i8042_pnp_kbd_registered = 1;
|
||||
i8042_pnp_kbd_registered = true;
|
||||
|
||||
err = pnp_register_driver(&i8042_pnp_aux_driver);
|
||||
if (!err)
|
||||
i8042_pnp_aux_registered = 1;
|
||||
i8042_pnp_aux_registered = true;
|
||||
|
||||
if (!i8042_pnp_kbd_devices && !i8042_pnp_aux_devices) {
|
||||
i8042_pnp_exit();
|
||||
|
@ -680,9 +708,9 @@ static int __init i8042_pnp_init(void)
|
|||
|
||||
#if defined(__ia64__)
|
||||
if (!i8042_pnp_kbd_devices)
|
||||
i8042_nokbd = 1;
|
||||
i8042_nokbd = true;
|
||||
if (!i8042_pnp_aux_devices)
|
||||
i8042_noaux = 1;
|
||||
i8042_noaux = true;
|
||||
#endif
|
||||
|
||||
if (((i8042_pnp_data_reg & ~0xf) == (i8042_data_reg & ~0xf) &&
|
||||
|
@ -693,7 +721,7 @@ static int __init i8042_pnp_init(void)
|
|||
"using default %#x\n",
|
||||
i8042_pnp_data_reg, i8042_data_reg);
|
||||
i8042_pnp_data_reg = i8042_data_reg;
|
||||
pnp_data_busted = 1;
|
||||
pnp_data_busted = true;
|
||||
}
|
||||
|
||||
if (((i8042_pnp_command_reg & ~0xf) == (i8042_command_reg & ~0xf) &&
|
||||
|
@ -704,7 +732,7 @@ static int __init i8042_pnp_init(void)
|
|||
"using default %#x\n",
|
||||
i8042_pnp_command_reg, i8042_command_reg);
|
||||
i8042_pnp_command_reg = i8042_command_reg;
|
||||
pnp_data_busted = 1;
|
||||
pnp_data_busted = true;
|
||||
}
|
||||
|
||||
if (!i8042_nokbd && !i8042_pnp_kbd_irq) {
|
||||
|
@ -712,7 +740,7 @@ static int __init i8042_pnp_init(void)
|
|||
"PNP: PS/2 controller doesn't have KBD irq; "
|
||||
"using default %d\n", i8042_kbd_irq);
|
||||
i8042_pnp_kbd_irq = i8042_kbd_irq;
|
||||
pnp_data_busted = 1;
|
||||
pnp_data_busted = true;
|
||||
}
|
||||
|
||||
if (!i8042_noaux && !i8042_pnp_aux_irq) {
|
||||
|
@ -721,7 +749,7 @@ static int __init i8042_pnp_init(void)
|
|||
"PNP: PS/2 appears to have AUX port disabled, "
|
||||
"if this is incorrect please boot with "
|
||||
"i8042.nopnp\n");
|
||||
i8042_noaux = 1;
|
||||
i8042_noaux = true;
|
||||
} else {
|
||||
printk(KERN_WARNING
|
||||
"PNP: PS/2 controller doesn't have AUX irq; "
|
||||
|
@ -735,6 +763,11 @@ static int __init i8042_pnp_init(void)
|
|||
i8042_kbd_irq = i8042_pnp_kbd_irq;
|
||||
i8042_aux_irq = i8042_pnp_aux_irq;
|
||||
|
||||
#ifdef CONFIG_X86
|
||||
i8042_bypass_aux_irq_test = !pnp_data_busted &&
|
||||
dmi_check_system(i8042_dmi_laptop_table);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -763,21 +796,21 @@ static int __init i8042_platform_init(void)
|
|||
return retval;
|
||||
|
||||
#if defined(__ia64__)
|
||||
i8042_reset = 1;
|
||||
i8042_reset = true;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_X86
|
||||
if (dmi_check_system(i8042_dmi_reset_table))
|
||||
i8042_reset = 1;
|
||||
i8042_reset = true;
|
||||
|
||||
if (dmi_check_system(i8042_dmi_noloop_table))
|
||||
i8042_noloop = 1;
|
||||
i8042_noloop = true;
|
||||
|
||||
if (dmi_check_system(i8042_dmi_nomux_table))
|
||||
i8042_nomux = 1;
|
||||
i8042_nomux = true;
|
||||
|
||||
if (dmi_check_system(i8042_dmi_dritek_table))
|
||||
i8042_dritek = 1;
|
||||
i8042_dritek = true;
|
||||
#endif /* CONFIG_X86 */
|
||||
|
||||
return retval;
|
||||
|
|
|
@ -28,35 +28,35 @@ MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
|
|||
MODULE_DESCRIPTION("i8042 keyboard and mouse controller driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
static unsigned int i8042_nokbd;
|
||||
static bool i8042_nokbd;
|
||||
module_param_named(nokbd, i8042_nokbd, bool, 0);
|
||||
MODULE_PARM_DESC(nokbd, "Do not probe or use KBD port.");
|
||||
|
||||
static unsigned int i8042_noaux;
|
||||
static bool i8042_noaux;
|
||||
module_param_named(noaux, i8042_noaux, bool, 0);
|
||||
MODULE_PARM_DESC(noaux, "Do not probe or use AUX (mouse) port.");
|
||||
|
||||
static unsigned int i8042_nomux;
|
||||
static bool i8042_nomux;
|
||||
module_param_named(nomux, i8042_nomux, bool, 0);
|
||||
MODULE_PARM_DESC(nomux, "Do not check whether an active multiplexing conrtoller is present.");
|
||||
|
||||
static unsigned int i8042_unlock;
|
||||
static bool i8042_unlock;
|
||||
module_param_named(unlock, i8042_unlock, bool, 0);
|
||||
MODULE_PARM_DESC(unlock, "Ignore keyboard lock.");
|
||||
|
||||
static unsigned int i8042_reset;
|
||||
static bool i8042_reset;
|
||||
module_param_named(reset, i8042_reset, bool, 0);
|
||||
MODULE_PARM_DESC(reset, "Reset controller during init and cleanup.");
|
||||
|
||||
static unsigned int i8042_direct;
|
||||
static bool i8042_direct;
|
||||
module_param_named(direct, i8042_direct, bool, 0);
|
||||
MODULE_PARM_DESC(direct, "Put keyboard port into non-translated mode.");
|
||||
|
||||
static unsigned int i8042_dumbkbd;
|
||||
static bool i8042_dumbkbd;
|
||||
module_param_named(dumbkbd, i8042_dumbkbd, bool, 0);
|
||||
MODULE_PARM_DESC(dumbkbd, "Pretend that controller can only read data from keyboard");
|
||||
|
||||
static unsigned int i8042_noloop;
|
||||
static bool i8042_noloop;
|
||||
module_param_named(noloop, i8042_noloop, bool, 0);
|
||||
MODULE_PARM_DESC(noloop, "Disable the AUX Loopback command while probing for the AUX port");
|
||||
|
||||
|
@ -65,24 +65,26 @@ module_param_named(panicblink, i8042_blink_frequency, uint, 0600);
|
|||
MODULE_PARM_DESC(panicblink, "Frequency with which keyboard LEDs should blink when kernel panics");
|
||||
|
||||
#ifdef CONFIG_X86
|
||||
static unsigned int i8042_dritek;
|
||||
static bool i8042_dritek;
|
||||
module_param_named(dritek, i8042_dritek, bool, 0);
|
||||
MODULE_PARM_DESC(dritek, "Force enable the Dritek keyboard extension");
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PNP
|
||||
static int i8042_nopnp;
|
||||
static bool i8042_nopnp;
|
||||
module_param_named(nopnp, i8042_nopnp, bool, 0);
|
||||
MODULE_PARM_DESC(nopnp, "Do not use PNP to detect controller settings");
|
||||
#endif
|
||||
|
||||
#define DEBUG
|
||||
#ifdef DEBUG
|
||||
static int i8042_debug;
|
||||
static bool i8042_debug;
|
||||
module_param_named(debug, i8042_debug, bool, 0600);
|
||||
MODULE_PARM_DESC(debug, "Turn i8042 debugging mode on and off");
|
||||
#endif
|
||||
|
||||
static bool i8042_bypass_aux_irq_test;
|
||||
|
||||
#include "i8042.h"
|
||||
|
||||
static DEFINE_SPINLOCK(i8042_lock);
|
||||
|
@ -90,7 +92,7 @@ static DEFINE_SPINLOCK(i8042_lock);
|
|||
struct i8042_port {
|
||||
struct serio *serio;
|
||||
int irq;
|
||||
unsigned char exists;
|
||||
bool exists;
|
||||
signed char mux;
|
||||
};
|
||||
|
||||
|
@ -103,9 +105,9 @@ static struct i8042_port i8042_ports[I8042_NUM_PORTS];
|
|||
|
||||
static unsigned char i8042_initial_ctr;
|
||||
static unsigned char i8042_ctr;
|
||||
static unsigned char i8042_mux_present;
|
||||
static unsigned char i8042_kbd_irq_registered;
|
||||
static unsigned char i8042_aux_irq_registered;
|
||||
static bool i8042_mux_present;
|
||||
static bool i8042_kbd_irq_registered;
|
||||
static bool i8042_aux_irq_registered;
|
||||
static unsigned char i8042_suppress_kbd_ack;
|
||||
static struct platform_device *i8042_platform_device;
|
||||
|
||||
|
@ -262,6 +264,49 @@ static int i8042_aux_write(struct serio *serio, unsigned char c)
|
|||
I8042_CMD_MUX_SEND + port->mux);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* i8042_aux_close attempts to clear AUX or KBD port state by disabling
|
||||
* and then re-enabling it.
|
||||
*/
|
||||
|
||||
static void i8042_port_close(struct serio *serio)
|
||||
{
|
||||
int irq_bit;
|
||||
int disable_bit;
|
||||
const char *port_name;
|
||||
|
||||
if (serio == i8042_ports[I8042_AUX_PORT_NO].serio) {
|
||||
irq_bit = I8042_CTR_AUXINT;
|
||||
disable_bit = I8042_CTR_AUXDIS;
|
||||
port_name = "AUX";
|
||||
} else {
|
||||
irq_bit = I8042_CTR_KBDINT;
|
||||
disable_bit = I8042_CTR_KBDDIS;
|
||||
port_name = "KBD";
|
||||
}
|
||||
|
||||
i8042_ctr &= ~irq_bit;
|
||||
if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR))
|
||||
printk(KERN_WARNING
|
||||
"i8042.c: Can't write CTR while closing %s port.\n",
|
||||
port_name);
|
||||
|
||||
udelay(50);
|
||||
|
||||
i8042_ctr &= ~disable_bit;
|
||||
i8042_ctr |= irq_bit;
|
||||
if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR))
|
||||
printk(KERN_ERR "i8042.c: Can't reactivate %s port.\n",
|
||||
port_name);
|
||||
|
||||
/*
|
||||
* See if there is any data appeared while we were messing with
|
||||
* port state.
|
||||
*/
|
||||
i8042_interrupt(0, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* i8042_start() is called by serio core when port is about to finish
|
||||
* registering. It will mark port as existing so i8042_interrupt can
|
||||
|
@ -271,7 +316,7 @@ static int i8042_start(struct serio *serio)
|
|||
{
|
||||
struct i8042_port *port = serio->port_data;
|
||||
|
||||
port->exists = 1;
|
||||
port->exists = true;
|
||||
mb();
|
||||
return 0;
|
||||
}
|
||||
|
@ -285,7 +330,7 @@ static void i8042_stop(struct serio *serio)
|
|||
{
|
||||
struct i8042_port *port = serio->port_data;
|
||||
|
||||
port->exists = 0;
|
||||
port->exists = false;
|
||||
|
||||
/*
|
||||
* We synchronize with both AUX and KBD IRQs because there is
|
||||
|
@ -391,7 +436,7 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id)
|
|||
}
|
||||
|
||||
/*
|
||||
* i8042_enable_kbd_port enables keybaord port on chip
|
||||
* i8042_enable_kbd_port enables keyboard port on chip
|
||||
*/
|
||||
|
||||
static int i8042_enable_kbd_port(void)
|
||||
|
@ -447,14 +492,15 @@ static int i8042_enable_mux_ports(void)
|
|||
}
|
||||
|
||||
/*
|
||||
* i8042_set_mux_mode checks whether the controller has an active
|
||||
* multiplexor and puts the chip into Multiplexed (1) or Legacy (0) mode.
|
||||
* i8042_set_mux_mode checks whether the controller has an
|
||||
* active multiplexor and puts the chip into Multiplexed (true)
|
||||
* or Legacy (false) mode.
|
||||
*/
|
||||
|
||||
static int i8042_set_mux_mode(unsigned int mode, unsigned char *mux_version)
|
||||
static int i8042_set_mux_mode(bool multiplex, unsigned char *mux_version)
|
||||
{
|
||||
|
||||
unsigned char param;
|
||||
unsigned char param, val;
|
||||
/*
|
||||
* Get rid of bytes in the queue.
|
||||
*/
|
||||
|
@ -466,14 +512,21 @@ static int i8042_set_mux_mode(unsigned int mode, unsigned char *mux_version)
|
|||
* mouse interface, the last should be version.
|
||||
*/
|
||||
|
||||
param = 0xf0;
|
||||
if (i8042_command(¶m, I8042_CMD_AUX_LOOP) || param != 0xf0)
|
||||
param = val = 0xf0;
|
||||
if (i8042_command(¶m, I8042_CMD_AUX_LOOP) || param != val)
|
||||
return -1;
|
||||
param = mode ? 0x56 : 0xf6;
|
||||
if (i8042_command(¶m, I8042_CMD_AUX_LOOP) || param != (mode ? 0x56 : 0xf6))
|
||||
param = val = multiplex ? 0x56 : 0xf6;
|
||||
if (i8042_command(¶m, I8042_CMD_AUX_LOOP) || param != val)
|
||||
return -1;
|
||||
param = mode ? 0xa4 : 0xa5;
|
||||
if (i8042_command(¶m, I8042_CMD_AUX_LOOP) || param == (mode ? 0xa4 : 0xa5))
|
||||
param = val = multiplex ? 0xa4 : 0xa5;
|
||||
if (i8042_command(¶m, I8042_CMD_AUX_LOOP) || param == val)
|
||||
return -1;
|
||||
|
||||
/*
|
||||
* Workaround for interference with USB Legacy emulation
|
||||
* that causes a v10.12 MUX to be found.
|
||||
*/
|
||||
if (param == 0xac)
|
||||
return -1;
|
||||
|
||||
if (mux_version)
|
||||
|
@ -488,18 +541,11 @@ static int i8042_set_mux_mode(unsigned int mode, unsigned char *mux_version)
|
|||
* LCS/Telegraphics.
|
||||
*/
|
||||
|
||||
static int __devinit i8042_check_mux(void)
|
||||
static int __init i8042_check_mux(void)
|
||||
{
|
||||
unsigned char mux_version;
|
||||
|
||||
if (i8042_set_mux_mode(1, &mux_version))
|
||||
return -1;
|
||||
|
||||
/*
|
||||
* Workaround for interference with USB Legacy emulation
|
||||
* that causes a v10.12 MUX to be found.
|
||||
*/
|
||||
if (mux_version == 0xAC)
|
||||
if (i8042_set_mux_mode(true, &mux_version))
|
||||
return -1;
|
||||
|
||||
printk(KERN_INFO "i8042.c: Detected active multiplexing controller, rev %d.%d.\n",
|
||||
|
@ -516,7 +562,7 @@ static int __devinit i8042_check_mux(void)
|
|||
return -EIO;
|
||||
}
|
||||
|
||||
i8042_mux_present = 1;
|
||||
i8042_mux_present = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -524,10 +570,10 @@ static int __devinit i8042_check_mux(void)
|
|||
/*
|
||||
* The following is used to test AUX IRQ delivery.
|
||||
*/
|
||||
static struct completion i8042_aux_irq_delivered __devinitdata;
|
||||
static int i8042_irq_being_tested __devinitdata;
|
||||
static struct completion i8042_aux_irq_delivered __initdata;
|
||||
static bool i8042_irq_being_tested __initdata;
|
||||
|
||||
static irqreturn_t __devinit i8042_aux_test_irq(int irq, void *dev_id)
|
||||
static irqreturn_t __init i8042_aux_test_irq(int irq, void *dev_id)
|
||||
{
|
||||
unsigned long flags;
|
||||
unsigned char str, data;
|
||||
|
@ -552,7 +598,7 @@ static irqreturn_t __devinit i8042_aux_test_irq(int irq, void *dev_id)
|
|||
* verifies success by readinng CTR. Used when testing for presence of AUX
|
||||
* port.
|
||||
*/
|
||||
static int __devinit i8042_toggle_aux(int on)
|
||||
static int __init i8042_toggle_aux(bool on)
|
||||
{
|
||||
unsigned char param;
|
||||
int i;
|
||||
|
@ -580,11 +626,11 @@ static int __devinit i8042_toggle_aux(int on)
|
|||
* the presence of an AUX interface.
|
||||
*/
|
||||
|
||||
static int __devinit i8042_check_aux(void)
|
||||
static int __init i8042_check_aux(void)
|
||||
{
|
||||
int retval = -1;
|
||||
int irq_registered = 0;
|
||||
int aux_loop_broken = 0;
|
||||
bool irq_registered = false;
|
||||
bool aux_loop_broken = false;
|
||||
unsigned long flags;
|
||||
unsigned char param;
|
||||
|
||||
|
@ -621,19 +667,19 @@ static int __devinit i8042_check_aux(void)
|
|||
* mark it as broken
|
||||
*/
|
||||
if (!retval)
|
||||
aux_loop_broken = 1;
|
||||
aux_loop_broken = true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Bit assignment test - filters out PS/2 i8042's in AT mode
|
||||
*/
|
||||
|
||||
if (i8042_toggle_aux(0)) {
|
||||
if (i8042_toggle_aux(false)) {
|
||||
printk(KERN_WARNING "Failed to disable AUX port, but continuing anyway... Is this a SiS?\n");
|
||||
printk(KERN_WARNING "If AUX port is really absent please use the 'i8042.noaux' option.\n");
|
||||
}
|
||||
|
||||
if (i8042_toggle_aux(1))
|
||||
if (i8042_toggle_aux(true))
|
||||
return -1;
|
||||
|
||||
/*
|
||||
|
@ -641,7 +687,7 @@ static int __devinit i8042_check_aux(void)
|
|||
* used it for a PCI card or somethig else.
|
||||
*/
|
||||
|
||||
if (i8042_noloop || aux_loop_broken) {
|
||||
if (i8042_noloop || i8042_bypass_aux_irq_test || aux_loop_broken) {
|
||||
/*
|
||||
* Without LOOP command we can't test AUX IRQ delivery. Assume the port
|
||||
* is working and hope we are right.
|
||||
|
@ -654,7 +700,7 @@ static int __devinit i8042_check_aux(void)
|
|||
"i8042", i8042_platform_device))
|
||||
goto out;
|
||||
|
||||
irq_registered = 1;
|
||||
irq_registered = true;
|
||||
|
||||
if (i8042_enable_aux_port())
|
||||
goto out;
|
||||
|
@ -662,7 +708,7 @@ static int __devinit i8042_check_aux(void)
|
|||
spin_lock_irqsave(&i8042_lock, flags);
|
||||
|
||||
init_completion(&i8042_aux_irq_delivered);
|
||||
i8042_irq_being_tested = 1;
|
||||
i8042_irq_being_tested = true;
|
||||
|
||||
param = 0xa5;
|
||||
retval = __i8042_command(¶m, I8042_CMD_AUX_LOOP & 0xf0ff);
|
||||
|
@ -799,7 +845,7 @@ static int i8042_controller_init(void)
|
|||
*/
|
||||
|
||||
if (~i8042_ctr & I8042_CTR_XLATE)
|
||||
i8042_direct = 1;
|
||||
i8042_direct = true;
|
||||
|
||||
/*
|
||||
* Set nontranslated mode for the kbd interface if requested by an option.
|
||||
|
@ -839,12 +885,15 @@ static void i8042_controller_reset(void)
|
|||
i8042_ctr |= I8042_CTR_KBDDIS | I8042_CTR_AUXDIS;
|
||||
i8042_ctr &= ~(I8042_CTR_KBDINT | I8042_CTR_AUXINT);
|
||||
|
||||
if (i8042_command(&i8042_initial_ctr, I8042_CMD_CTL_WCTR))
|
||||
printk(KERN_WARNING "i8042.c: Can't write CTR while resetting.\n");
|
||||
|
||||
/*
|
||||
* Disable MUX mode if present.
|
||||
*/
|
||||
|
||||
if (i8042_mux_present)
|
||||
i8042_set_mux_mode(0, NULL);
|
||||
i8042_set_mux_mode(false, NULL);
|
||||
|
||||
/*
|
||||
* Reset the controller if requested.
|
||||
|
@ -923,41 +972,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;
|
||||
|
@ -991,7 +1026,7 @@ static int i8042_resume(struct platform_device *dev)
|
|||
#endif
|
||||
|
||||
if (i8042_mux_present) {
|
||||
if (i8042_set_mux_mode(1, NULL) || i8042_enable_mux_ports())
|
||||
if (i8042_set_mux_mode(true, NULL) || i8042_enable_mux_ports())
|
||||
printk(KERN_WARNING
|
||||
"i8042: failed to resume active multiplexor, "
|
||||
"mouse won't work.\n");
|
||||
|
@ -1001,11 +1036,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 */
|
||||
|
||||
/*
|
||||
|
@ -1018,7 +1060,7 @@ static void i8042_shutdown(struct platform_device *dev)
|
|||
i8042_controller_reset();
|
||||
}
|
||||
|
||||
static int __devinit i8042_create_kbd_port(void)
|
||||
static int __init i8042_create_kbd_port(void)
|
||||
{
|
||||
struct serio *serio;
|
||||
struct i8042_port *port = &i8042_ports[I8042_KBD_PORT_NO];
|
||||
|
@ -1031,6 +1073,7 @@ static int __devinit i8042_create_kbd_port(void)
|
|||
serio->write = i8042_dumbkbd ? NULL : i8042_kbd_write;
|
||||
serio->start = i8042_start;
|
||||
serio->stop = i8042_stop;
|
||||
serio->close = i8042_port_close;
|
||||
serio->port_data = port;
|
||||
serio->dev.parent = &i8042_platform_device->dev;
|
||||
strlcpy(serio->name, "i8042 KBD port", sizeof(serio->name));
|
||||
|
@ -1042,7 +1085,7 @@ static int __devinit i8042_create_kbd_port(void)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int __devinit i8042_create_aux_port(int idx)
|
||||
static int __init i8042_create_aux_port(int idx)
|
||||
{
|
||||
struct serio *serio;
|
||||
int port_no = idx < 0 ? I8042_AUX_PORT_NO : I8042_MUX_PORT_NO + idx;
|
||||
|
@ -1061,6 +1104,7 @@ static int __devinit i8042_create_aux_port(int idx)
|
|||
if (idx < 0) {
|
||||
strlcpy(serio->name, "i8042 AUX port", sizeof(serio->name));
|
||||
strlcpy(serio->phys, I8042_AUX_PHYS_DESC, sizeof(serio->phys));
|
||||
serio->close = i8042_port_close;
|
||||
} else {
|
||||
snprintf(serio->name, sizeof(serio->name), "i8042 AUX%d port", idx);
|
||||
snprintf(serio->phys, sizeof(serio->phys), I8042_MUX_PHYS_DESC, idx + 1);
|
||||
|
@ -1073,13 +1117,13 @@ static int __devinit i8042_create_aux_port(int idx)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void __devinit i8042_free_kbd_port(void)
|
||||
static void __init i8042_free_kbd_port(void)
|
||||
{
|
||||
kfree(i8042_ports[I8042_KBD_PORT_NO].serio);
|
||||
i8042_ports[I8042_KBD_PORT_NO].serio = NULL;
|
||||
}
|
||||
|
||||
static void __devinit i8042_free_aux_ports(void)
|
||||
static void __init i8042_free_aux_ports(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
|
@ -1089,7 +1133,7 @@ static void __devinit i8042_free_aux_ports(void)
|
|||
}
|
||||
}
|
||||
|
||||
static void __devinit i8042_register_ports(void)
|
||||
static void __init i8042_register_ports(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
|
@ -1124,10 +1168,10 @@ static void i8042_free_irqs(void)
|
|||
if (i8042_kbd_irq_registered)
|
||||
free_irq(I8042_KBD_IRQ, i8042_platform_device);
|
||||
|
||||
i8042_aux_irq_registered = i8042_kbd_irq_registered = 0;
|
||||
i8042_aux_irq_registered = i8042_kbd_irq_registered = false;
|
||||
}
|
||||
|
||||
static int __devinit i8042_setup_aux(void)
|
||||
static int __init i8042_setup_aux(void)
|
||||
{
|
||||
int (*aux_enable)(void);
|
||||
int error;
|
||||
|
@ -1158,7 +1202,7 @@ static int __devinit i8042_setup_aux(void)
|
|||
if (aux_enable())
|
||||
goto err_free_irq;
|
||||
|
||||
i8042_aux_irq_registered = 1;
|
||||
i8042_aux_irq_registered = true;
|
||||
return 0;
|
||||
|
||||
err_free_irq:
|
||||
|
@ -1168,7 +1212,7 @@ static int __devinit i8042_setup_aux(void)
|
|||
return error;
|
||||
}
|
||||
|
||||
static int __devinit i8042_setup_kbd(void)
|
||||
static int __init i8042_setup_kbd(void)
|
||||
{
|
||||
int error;
|
||||
|
||||
|
@ -1185,7 +1229,7 @@ static int __devinit i8042_setup_kbd(void)
|
|||
if (error)
|
||||
goto err_free_irq;
|
||||
|
||||
i8042_kbd_irq_registered = 1;
|
||||
i8042_kbd_irq_registered = true;
|
||||
return 0;
|
||||
|
||||
err_free_irq:
|
||||
|
@ -1195,7 +1239,7 @@ static int __devinit i8042_setup_kbd(void)
|
|||
return error;
|
||||
}
|
||||
|
||||
static int __devinit i8042_probe(struct platform_device *dev)
|
||||
static int __init i8042_probe(struct platform_device *dev)
|
||||
{
|
||||
int error;
|
||||
|
||||
|
@ -1251,14 +1295,12 @@ 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)
|
||||
|
@ -1275,28 +1317,28 @@ static int __init i8042_init(void)
|
|||
if (err)
|
||||
goto err_platform_exit;
|
||||
|
||||
err = platform_driver_register(&i8042_driver);
|
||||
if (err)
|
||||
goto err_platform_exit;
|
||||
|
||||
i8042_platform_device = platform_device_alloc("i8042", -1);
|
||||
if (!i8042_platform_device) {
|
||||
err = -ENOMEM;
|
||||
goto err_unregister_driver;
|
||||
goto err_platform_exit;
|
||||
}
|
||||
|
||||
err = platform_device_add(i8042_platform_device);
|
||||
if (err)
|
||||
goto err_free_device;
|
||||
|
||||
err = platform_driver_probe(&i8042_driver, i8042_probe);
|
||||
if (err)
|
||||
goto err_del_device;
|
||||
|
||||
panic_blink = i8042_panic_blink;
|
||||
|
||||
return 0;
|
||||
|
||||
err_del_device:
|
||||
platform_device_del(i8042_platform_device);
|
||||
err_free_device:
|
||||
platform_device_put(i8042_platform_device);
|
||||
err_unregister_driver:
|
||||
platform_driver_unregister(&i8042_driver);
|
||||
err_platform_exit:
|
||||
i8042_platform_exit();
|
||||
|
||||
|
@ -1305,8 +1347,8 @@ static int __init i8042_init(void)
|
|||
|
||||
static void __exit i8042_exit(void)
|
||||
{
|
||||
platform_device_unregister(i8042_platform_device);
|
||||
platform_driver_unregister(&i8042_driver);
|
||||
platform_device_unregister(i8042_platform_device);
|
||||
i8042_platform_exit();
|
||||
|
||||
panic_blink = NULL;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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 @@ static int __devinit atmel_tsadcc_probe(struct platform_device *pdev)
|
|||
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);
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,9 +31,11 @@
|
|||
#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 @@ static int wm97xx_acc_pen_down(struct wm97xx *wm)
|
|||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -21,15 +21,14 @@
|
|||
*/
|
||||
|
||||
#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);
|
||||
|
||||
x = ts->tc.x;
|
||||
y = ts->tc.y;
|
||||
z1 = ts->tc.z1;
|
||||
z2 = ts->tc.z2;
|
||||
/* 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);
|
||||
|
||||
/* 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;
|
||||
|
||||
/* 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
|
||||
*/
|
||||
if (rt > MAX_12BIT) {
|
||||
dev_dbg(&ts->client->dev, "ignored pressure %d\n", rt);
|
||||
|
||||
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.
|
||||
return rt;
|
||||
}
|
||||
|
||||
static void tsc2007_send_up_event(struct tsc2007 *tsc)
|
||||
{
|
||||
struct input_dev *input = tsc->input;
|
||||
|
||||
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
|
||||
* timer by reading the pen signal state (it's a GPIO _and_ IRQ).
|
||||
* 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;
|
||||
|
||||
}
|
||||
|
||||
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)
|
||||
|
|
|
@ -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);
|
||||
|
||||
/*
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -25,18 +25,16 @@ MODULE_AUTHOR("Jaya Kumar <jayakumar.lkml@gmail.com>");
|
|||
MODULE_DESCRIPTION(DRIVER_DESC);
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
/*
|
||||
* Definitions & global arrays.
|
||||
*/
|
||||
|
||||
#define W8001_MAX_LENGTH 11
|
||||
#define W8001_PACKET_LEN 11
|
||||
#define W8001_LEAD_MASK 0x80
|
||||
#define W8001_LEAD_BYTE 0x80
|
||||
#define W8001_TAB_MASK 0x40
|
||||
#define W8001_TAB_BYTE 0x40
|
||||
#define W8001_LEAD_MASK 0x80
|
||||
#define W8001_LEAD_BYTE 0x80
|
||||
#define W8001_TAB_MASK 0x40
|
||||
#define W8001_TAB_BYTE 0x40
|
||||
|
||||
#define W8001_QUERY_PACKET 0x20
|
||||
#define W8001_QUERY_PACKET 0x20
|
||||
|
||||
#define W8001_CMD_START '1'
|
||||
#define W8001_CMD_QUERY '*'
|
||||
|
||||
struct w8001_coord {
|
||||
u8 rdy;
|
||||
|
@ -57,18 +55,19 @@ struct w8001_coord {
|
|||
struct w8001 {
|
||||
struct input_dev *dev;
|
||||
struct serio *serio;
|
||||
struct mutex cmd_mutex;
|
||||
struct completion cmd_done;
|
||||
int id;
|
||||
int idx;
|
||||
unsigned char expected_packet;
|
||||
unsigned char response_type;
|
||||
unsigned char response[W8001_MAX_LENGTH];
|
||||
unsigned char data[W8001_MAX_LENGTH];
|
||||
unsigned char response[W8001_PACKET_LEN];
|
||||
char phys[32];
|
||||
};
|
||||
|
||||
static int parse_data(u8 *data, struct w8001_coord *coord)
|
||||
static void parse_data(u8 *data, struct w8001_coord *coord)
|
||||
{
|
||||
memset(coord, 0, sizeof(*coord));
|
||||
|
||||
coord->rdy = data[0] & 0x20;
|
||||
coord->tsw = data[0] & 0x01;
|
||||
coord->f1 = data[0] & 0x02;
|
||||
|
@ -87,15 +86,15 @@ static int parse_data(u8 *data, struct w8001_coord *coord)
|
|||
|
||||
coord->tilt_x = data[7] & 0x7F;
|
||||
coord->tilt_y = data[8] & 0x7F;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void w8001_process_data(struct w8001 *w8001, unsigned char data)
|
||||
static irqreturn_t w8001_interrupt(struct serio *serio,
|
||||
unsigned char data, unsigned int flags)
|
||||
{
|
||||
struct w8001 *w8001 = serio_get_drvdata(serio);
|
||||
struct input_dev *dev = w8001->dev;
|
||||
u8 tmp;
|
||||
struct w8001_coord coord;
|
||||
unsigned char tmp;
|
||||
|
||||
w8001->data[w8001->idx] = data;
|
||||
switch (w8001->idx++) {
|
||||
|
@ -105,12 +104,13 @@ static void w8001_process_data(struct w8001 *w8001, unsigned char data)
|
|||
w8001->idx = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case 8:
|
||||
tmp = w8001->data[0] & W8001_TAB_MASK;
|
||||
if (unlikely(tmp == W8001_TAB_BYTE))
|
||||
break;
|
||||
|
||||
w8001->idx = 0;
|
||||
memset(&coord, 0, sizeof(coord));
|
||||
parse_data(w8001->data, &coord);
|
||||
input_report_abs(dev, ABS_X, coord.x);
|
||||
input_report_abs(dev, ABS_Y, coord.y);
|
||||
|
@ -118,86 +118,48 @@ static void w8001_process_data(struct w8001 *w8001, unsigned char data)
|
|||
input_report_key(dev, BTN_TOUCH, coord.tsw);
|
||||
input_sync(dev);
|
||||
break;
|
||||
|
||||
case 10:
|
||||
w8001->idx = 0;
|
||||
memcpy(w8001->response, &w8001->data, W8001_PACKET_LEN);
|
||||
w8001->expected_packet = W8001_QUERY_PACKET;
|
||||
memcpy(w8001->response, w8001->data, W8001_MAX_LENGTH);
|
||||
w8001->response_type = W8001_QUERY_PACKET;
|
||||
complete(&w8001->cmd_done);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static irqreturn_t w8001_interrupt(struct serio *serio,
|
||||
unsigned char data, unsigned int flags)
|
||||
{
|
||||
struct w8001 *w8001 = serio_get_drvdata(serio);
|
||||
|
||||
w8001_process_data(w8001, data);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int w8001_async_command(struct w8001 *w8001, unsigned char *packet,
|
||||
int len)
|
||||
static int w8001_command(struct w8001 *w8001, unsigned char command,
|
||||
bool wait_response)
|
||||
{
|
||||
int rc = -1;
|
||||
int i;
|
||||
int rc;
|
||||
|
||||
mutex_lock(&w8001->cmd_mutex);
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
if (serio_write(w8001->serio, packet[i]))
|
||||
goto out;
|
||||
}
|
||||
rc = 0;
|
||||
|
||||
out:
|
||||
mutex_unlock(&w8001->cmd_mutex);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int w8001_command(struct w8001 *w8001, unsigned char *packet, int len)
|
||||
{
|
||||
int rc = -1;
|
||||
int i;
|
||||
|
||||
mutex_lock(&w8001->cmd_mutex);
|
||||
|
||||
serio_pause_rx(w8001->serio);
|
||||
w8001->response_type = 0;
|
||||
init_completion(&w8001->cmd_done);
|
||||
serio_continue_rx(w8001->serio);
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
if (serio_write(w8001->serio, packet[i]))
|
||||
goto out;
|
||||
rc = serio_write(w8001->serio, command);
|
||||
if (rc == 0 && wait_response) {
|
||||
|
||||
wait_for_completion_timeout(&w8001->cmd_done, HZ);
|
||||
if (w8001->response_type != W8001_QUERY_PACKET)
|
||||
rc = -EIO;
|
||||
}
|
||||
|
||||
wait_for_completion_timeout(&w8001->cmd_done, HZ);
|
||||
|
||||
if (w8001->expected_packet == W8001_QUERY_PACKET) {
|
||||
/* We are back in reporting mode, the query was ACKed */
|
||||
memcpy(packet, w8001->response, W8001_PACKET_LEN);
|
||||
rc = 0;
|
||||
}
|
||||
|
||||
out:
|
||||
mutex_unlock(&w8001->cmd_mutex);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int w8001_setup(struct w8001 *w8001)
|
||||
{
|
||||
struct w8001_coord coord;
|
||||
struct input_dev *dev = w8001->dev;
|
||||
unsigned char start[1] = { '1' };
|
||||
unsigned char query[11] = { '*' };
|
||||
struct w8001_coord coord;
|
||||
int error;
|
||||
|
||||
if (w8001_command(w8001, query, 1))
|
||||
return -1;
|
||||
error = w8001_command(w8001, W8001_CMD_QUERY, true);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
memset(&coord, 0, sizeof(coord));
|
||||
parse_data(query, &coord);
|
||||
parse_data(w8001->response, &coord);
|
||||
|
||||
input_set_abs_params(dev, ABS_X, 0, coord.x, 0, 0);
|
||||
input_set_abs_params(dev, ABS_Y, 0, coord.y, 0, 0);
|
||||
|
@ -205,10 +167,7 @@ static int w8001_setup(struct w8001 *w8001)
|
|||
input_set_abs_params(dev, ABS_TILT_X, 0, coord.tilt_x, 0, 0);
|
||||
input_set_abs_params(dev, ABS_TILT_Y, 0, coord.tilt_y, 0, 0);
|
||||
|
||||
if (w8001_async_command(w8001, start, 1))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
return w8001_command(w8001, W8001_CMD_START, false);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -249,7 +208,6 @@ static int w8001_connect(struct serio *serio, struct serio_driver *drv)
|
|||
w8001->serio = serio;
|
||||
w8001->id = serio->id.id;
|
||||
w8001->dev = input_dev;
|
||||
mutex_init(&w8001->cmd_mutex);
|
||||
init_completion(&w8001->cmd_done);
|
||||
snprintf(w8001->phys, sizeof(w8001->phys), "%s/input0", serio->phys);
|
||||
|
||||
|
@ -269,7 +227,8 @@ static int w8001_connect(struct serio *serio, struct serio_driver *drv)
|
|||
if (err)
|
||||
goto fail2;
|
||||
|
||||
if (w8001_setup(w8001))
|
||||
err = w8001_setup(w8001);
|
||||
if (err)
|
||||
goto fail3;
|
||||
|
||||
err = input_register_device(w8001->dev);
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -25,6 +25,9 @@
|
|||
#ifndef __TWL4030_H_
|
||||
#define __TWL4030_H_
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/input/matrix_keypad.h>
|
||||
|
||||
/*
|
||||
* Using the twl4030 core we address registers using a pair
|
||||
* { module id, relative register offset }
|
||||
|
@ -302,13 +305,17 @@ struct twl4030_madc_platform_data {
|
|||
int irq_line;
|
||||
};
|
||||
|
||||
/* Boards have uniqe mappings of {col, row} --> keycode.
|
||||
* Column and row are 4 bits, but range only from 0..7.
|
||||
* a PERSISTENT_KEY is "always on" and never reported.
|
||||
*/
|
||||
#define PERSISTENT_KEY(c, r) KEY((c), (r), KEY_RESERVED)
|
||||
|
||||
struct twl4030_keypad_data {
|
||||
int rows;
|
||||
int cols;
|
||||
int *keymap;
|
||||
int irq;
|
||||
unsigned int keymapsize;
|
||||
unsigned int rep:1;
|
||||
const struct matrix_keymap_data *keymap_data;
|
||||
unsigned rows;
|
||||
unsigned cols;
|
||||
bool rep;
|
||||
};
|
||||
|
||||
enum twl4030_usb_mode {
|
||||
|
|
9
include/linux/input/eeti_ts.h
Normal file
9
include/linux/input/eeti_ts.h
Normal file
|
@ -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 */
|
||||
|
|
@ -63,4 +63,36 @@ struct matrix_keypad_platform_data {
|
|||
bool wakeup;
|
||||
};
|
||||
|
||||
/**
|
||||
* matrix_keypad_build_keymap - convert platform keymap into matrix keymap
|
||||
* @keymap_data: keymap supplied by the platform code
|
||||
* @row_shift: number of bits to shift row value by to advance to the next
|
||||
* line in the keymap
|
||||
* @keymap: expanded version of keymap that is suitable for use by
|
||||
* matrix keyboad driver
|
||||
* @keybit: pointer to bitmap of keys supported by input device
|
||||
*
|
||||
* This function converts platform keymap (encoded with KEY() macro) into
|
||||
* an array of keycodes that is suitable for using in a standard matrix
|
||||
* keyboard driver that uses row and col as indices.
|
||||
*/
|
||||
static inline void
|
||||
matrix_keypad_build_keymap(const struct matrix_keymap_data *keymap_data,
|
||||
unsigned int row_shift,
|
||||
unsigned short *keymap, unsigned long *keybit)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < keymap_data->keymap_size; i++) {
|
||||
unsigned int key = keymap_data->keymap[i];
|
||||
unsigned int row = KEY_ROW(key);
|
||||
unsigned int col = KEY_COL(key);
|
||||
unsigned short code = KEY_VAL(key);
|
||||
|
||||
keymap[MATRIX_SCAN_CODE(row, col, row_shift)] = code;
|
||||
__set_bit(code, keybit);
|
||||
}
|
||||
__clear_bit(KEY_RESERVED, keybit);
|
||||
}
|
||||
|
||||
#endif /* _MATRIX_KEYPAD_H */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -15,6 +15,12 @@
|
|||
#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 */
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in a new issue