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:
Linus Torvalds 2009-09-14 17:56:51 -07:00
commit 133309a89e
77 changed files with 4352 additions and 1577 deletions

View 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

View file

@ -2,9 +2,12 @@
#define __ASM_ARCH_PXA27x_KEYPAD_H
#include <linux/input.h>
#include <linux/input/matrix_keypad.h>
#define MAX_MATRIX_KEY_ROWS (8)
#define MAX_MATRIX_KEY_COLS (8)
#define MATRIX_ROW_SHIFT (3)
#define MAX_DIRECT_KEY_NUM (8)
/* pxa3xx keypad platform specific parameters
*
@ -33,7 +36,7 @@ struct pxa27x_keypad_platform_data {
/* direct keys */
int direct_key_num;
unsigned int direct_key_map[8];
unsigned int direct_key_map[MAX_DIRECT_KEY_NUM];
/* rotary encoders 0 */
int enable_rotary0;
@ -51,8 +54,6 @@ struct pxa27x_keypad_platform_data {
unsigned int debounce_interval;
};
#define KEY(row, col, val) (((row) << 28) | ((col) << 24) | (val))
extern void pxa_set_keypad_info(struct pxa27x_keypad_platform_data *info);
#endif /* __ASM_ARCH_PXA27x_KEYPAD_H */

View 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 */

View 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

View file

@ -922,7 +922,7 @@ static int platform_pm_restore_noirq(struct device *dev)
#endif /* !CONFIG_HIBERNATION */
static struct dev_pm_ops platform_dev_pm_ops = {
static const struct dev_pm_ops platform_dev_pm_ops = {
.prepare = platform_pm_prepare,
.complete = platform_pm_complete,
.suspend = platform_pm_suspend,

View file

@ -157,8 +157,9 @@ void device_pm_move_last(struct device *dev)
* @ops: PM operations to choose from.
* @state: PM transition of the system being carried out.
*/
static int pm_op(struct device *dev, struct dev_pm_ops *ops,
pm_message_t state)
static int pm_op(struct device *dev,
const struct dev_pm_ops *ops,
pm_message_t state)
{
int error = 0;
@ -220,7 +221,8 @@ static int pm_op(struct device *dev, struct dev_pm_ops *ops,
* The operation is executed with interrupts disabled by the only remaining
* functional CPU in the system.
*/
static int pm_noirq_op(struct device *dev, struct dev_pm_ops *ops,
static int pm_noirq_op(struct device *dev,
const struct dev_pm_ops *ops,
pm_message_t state)
{
int error = 0;

View file

@ -452,6 +452,76 @@ static unsigned int joydev_poll(struct file *file, poll_table *wait)
(joydev->exist ? 0 : (POLLHUP | POLLERR));
}
static int joydev_handle_JSIOCSAXMAP(struct joydev *joydev,
void __user *argp, size_t len)
{
__u8 *abspam;
int i;
int retval = 0;
len = min(len, sizeof(joydev->abspam));
/* Validate the map. */
abspam = kmalloc(len, GFP_KERNEL);
if (!abspam)
return -ENOMEM;
if (copy_from_user(abspam, argp, len)) {
retval = -EFAULT;
goto out;
}
for (i = 0; i < joydev->nabs; i++) {
if (abspam[i] > ABS_MAX) {
retval = -EINVAL;
goto out;
}
}
memcpy(joydev->abspam, abspam, len);
out:
kfree(abspam);
return retval;
}
static int joydev_handle_JSIOCSBTNMAP(struct joydev *joydev,
void __user *argp, size_t len)
{
__u16 *keypam;
int i;
int retval = 0;
len = min(len, sizeof(joydev->keypam));
/* Validate the map. */
keypam = kmalloc(len, GFP_KERNEL);
if (!keypam)
return -ENOMEM;
if (copy_from_user(keypam, argp, len)) {
retval = -EFAULT;
goto out;
}
for (i = 0; i < joydev->nkey; i++) {
if (keypam[i] > KEY_MAX || keypam[i] < BTN_MISC) {
retval = -EINVAL;
goto out;
}
}
memcpy(joydev->keypam, keypam, len);
for (i = 0; i < joydev->nkey; i++)
joydev->keymap[keypam[i] - BTN_MISC] = i;
out:
kfree(keypam);
return retval;
}
static int joydev_ioctl_common(struct joydev *joydev,
unsigned int cmd, void __user *argp)
{
@ -512,46 +582,18 @@ static int joydev_ioctl_common(struct joydev *joydev,
switch (cmd & ~IOCSIZE_MASK) {
case (JSIOCSAXMAP & ~IOCSIZE_MASK):
len = min_t(size_t, _IOC_SIZE(cmd), sizeof(joydev->abspam));
/*
* FIXME: we should not copy into our axis map before
* validating the data.
*/
if (copy_from_user(joydev->abspam, argp, len))
return -EFAULT;
for (i = 0; i < joydev->nabs; i++) {
if (joydev->abspam[i] > ABS_MAX)
return -EINVAL;
joydev->absmap[joydev->abspam[i]] = i;
}
return 0;
return joydev_handle_JSIOCSAXMAP(joydev, argp, _IOC_SIZE(cmd));
case (JSIOCGAXMAP & ~IOCSIZE_MASK):
len = min_t(size_t, _IOC_SIZE(cmd), sizeof(joydev->abspam));
return copy_to_user(argp, joydev->abspam, len) ? -EFAULT : 0;
return copy_to_user(argp, joydev->abspam, len) ? -EFAULT : len;
case (JSIOCSBTNMAP & ~IOCSIZE_MASK):
len = min_t(size_t, _IOC_SIZE(cmd), sizeof(joydev->keypam));
/*
* FIXME: we should not copy into our keymap before
* validating the data.
*/
if (copy_from_user(joydev->keypam, argp, len))
return -EFAULT;
for (i = 0; i < joydev->nkey; i++) {
if (joydev->keypam[i] > KEY_MAX ||
joydev->keypam[i] < BTN_MISC)
return -EINVAL;
joydev->keymap[joydev->keypam[i] - BTN_MISC] = i;
}
return 0;
return joydev_handle_JSIOCSBTNMAP(joydev, argp, _IOC_SIZE(cmd));
case (JSIOCGBTNMAP & ~IOCSIZE_MASK):
len = min_t(size_t, _IOC_SIZE(cmd), sizeof(joydev->keypam));
return copy_to_user(argp, joydev->keypam, len) ? -EFAULT : 0;
return copy_to_user(argp, joydev->keypam, len) ? -EFAULT : len;
case JSIOCGNAME(0):
name = dev->name;

View file

@ -144,6 +144,7 @@ static const struct xpad_device {
{ 0x1430, 0x4748, "RedOctane Guitar Hero X-plorer", MAP_DPAD_TO_AXES, XTYPE_XBOX360 },
{ 0x1430, 0x8888, "TX6500+ Dance Pad (first generation)", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },
{ 0x045e, 0x028e, "Microsoft X-Box 360 pad", MAP_DPAD_TO_AXES, XTYPE_XBOX360 },
{ 0x1bad, 0x0003, "Harmonix Rock Band Drumkit", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 },
{ 0xffff, 0xffff, "Chinese-made Xbox Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
{ 0x0000, 0x0000, "Generic X-Box pad", MAP_DPAD_UNKNOWN, XTYPE_UNKNOWN }
};
@ -208,6 +209,7 @@ static struct usb_device_id xpad_table [] = {
XPAD_XBOX360_VENDOR(0x0738), /* Mad Catz X-Box 360 controllers */
XPAD_XBOX360_VENDOR(0x0e6f), /* 0x0e6f X-Box 360 controllers */
XPAD_XBOX360_VENDOR(0x1430), /* RedOctane X-Box 360 controllers */
XPAD_XBOX360_VENDOR(0x1bad), /* Rock Band Drums */
{ }
};

View file

@ -187,7 +187,7 @@ config KEYBOARD_HIL_OLD
submenu.
config KEYBOARD_HIL
tristate "HP HIL keyboard support"
tristate "HP HIL keyboard/pointer support"
depends on GSC || HP300
default y
select HP_SDC
@ -196,7 +196,8 @@ config KEYBOARD_HIL
help
The "Human Interface Loop" is a older, 8-channel USB-like
controller used in several Hewlett Packard models.
This driver implements support for HIL-keyboards attached
This driver implements support for HIL-keyboards and pointing
devices (mice, tablets, touchscreens) attached
to your machine, so normally you should say Y here.
config KEYBOARD_HP6XX
@ -329,6 +330,17 @@ config KEYBOARD_OMAP
To compile this driver as a module, choose M here: the
module will be called omap-keypad.
config KEYBOARD_TWL4030
tristate "TI TWL4030/TWL5030/TPS659x0 keypad support"
depends on TWL4030_CORE
help
Say Y here if your board use the keypad controller on
TWL4030 family chips. It's safe to say enable this
even on boards that don't use the keypad controller.
To compile this driver as a module, choose M here: the
module will be called twl4030_keypad.
config KEYBOARD_TOSA
tristate "Tosa keyboard"
depends on MACH_TOSA
@ -361,4 +373,14 @@ config KEYBOARD_XTKBD
To compile this driver as a module, choose M here: the
module will be called xtkbd.
config KEYBOARD_W90P910
tristate "W90P910 Matrix Keypad support"
depends on ARCH_W90X900
help
Say Y here to enable the matrix keypad on evaluation board
based on W90P910.
To compile this driver as a module, choose M here: the
module will be called w90p910_keypad.
endif

View file

@ -30,4 +30,6 @@ obj-$(CONFIG_KEYBOARD_SPITZ) += spitzkbd.o
obj-$(CONFIG_KEYBOARD_STOWAWAY) += stowaway.o
obj-$(CONFIG_KEYBOARD_SUNKBD) += sunkbd.o
obj-$(CONFIG_KEYBOARD_TOSA) += tosakbd.o
obj-$(CONFIG_KEYBOARD_TWL4030) += twl4030_keypad.o
obj-$(CONFIG_KEYBOARD_XTKBD) += xtkbd.o
obj-$(CONFIG_KEYBOARD_W90P910) += w90p910_keypad.o

View file

@ -68,7 +68,9 @@ MODULE_PARM_DESC(extra, "Enable extra LEDs and keys on IBM RapidAcces, EzKey and
* are loadable via a userland utility.
*/
static const unsigned short atkbd_set2_keycode[512] = {
#define ATKBD_KEYMAP_SIZE 512
static const unsigned short atkbd_set2_keycode[ATKBD_KEYMAP_SIZE] = {
#ifdef CONFIG_KEYBOARD_ATKBD_HP_KEYCODES
@ -99,7 +101,7 @@ static const unsigned short atkbd_set2_keycode[512] = {
#endif
};
static const unsigned short atkbd_set3_keycode[512] = {
static const unsigned short atkbd_set3_keycode[ATKBD_KEYMAP_SIZE] = {
0, 0, 0, 0, 0, 0, 0, 59, 1,138,128,129,130, 15, 41, 60,
131, 29, 42, 86, 58, 16, 2, 61,133, 56, 44, 31, 30, 17, 3, 62,
@ -200,8 +202,8 @@ struct atkbd {
char phys[32];
unsigned short id;
unsigned short keycode[512];
DECLARE_BITMAP(force_release_mask, 512);
unsigned short keycode[ATKBD_KEYMAP_SIZE];
DECLARE_BITMAP(force_release_mask, ATKBD_KEYMAP_SIZE);
unsigned char set;
unsigned char translated;
unsigned char extra;
@ -253,6 +255,7 @@ static struct device_attribute atkbd_attr_##_name = \
__ATTR(_name, S_IWUSR | S_IRUGO, atkbd_do_show_##_name, atkbd_do_set_##_name);
ATKBD_DEFINE_ATTR(extra);
ATKBD_DEFINE_ATTR(force_release);
ATKBD_DEFINE_ATTR(scroll);
ATKBD_DEFINE_ATTR(set);
ATKBD_DEFINE_ATTR(softrepeat);
@ -272,6 +275,7 @@ ATKBD_DEFINE_RO_ATTR(err_count);
static struct attribute *atkbd_attributes[] = {
&atkbd_attr_extra.attr,
&atkbd_attr_force_release.attr,
&atkbd_attr_scroll.attr,
&atkbd_attr_set.attr,
&atkbd_attr_softrepeat.attr,
@ -934,7 +938,7 @@ static void atkbd_set_keycode_table(struct atkbd *atkbd)
int i, j;
memset(atkbd->keycode, 0, sizeof(atkbd->keycode));
bitmap_zero(atkbd->force_release_mask, 512);
bitmap_zero(atkbd->force_release_mask, ATKBD_KEYMAP_SIZE);
if (atkbd->translated) {
for (i = 0; i < 128; i++) {
@ -1041,7 +1045,7 @@ static void atkbd_set_device_attrs(struct atkbd *atkbd)
input_dev->keycodesize = sizeof(unsigned short);
input_dev->keycodemax = ARRAY_SIZE(atkbd_set2_keycode);
for (i = 0; i < 512; i++)
for (i = 0; i < ATKBD_KEYMAP_SIZE; i++)
if (atkbd->keycode[i] && atkbd->keycode[i] < ATKBD_SPECIAL)
__set_bit(atkbd->keycode[i], input_dev->keybit);
}
@ -1309,6 +1313,33 @@ static ssize_t atkbd_set_extra(struct atkbd *atkbd, const char *buf, size_t coun
return count;
}
static ssize_t atkbd_show_force_release(struct atkbd *atkbd, char *buf)
{
size_t len = bitmap_scnlistprintf(buf, PAGE_SIZE - 2,
atkbd->force_release_mask, ATKBD_KEYMAP_SIZE);
buf[len++] = '\n';
buf[len] = '\0';
return len;
}
static ssize_t atkbd_set_force_release(struct atkbd *atkbd,
const char *buf, size_t count)
{
/* 64 bytes on stack should be acceptable */
DECLARE_BITMAP(new_mask, ATKBD_KEYMAP_SIZE);
int err;
err = bitmap_parselist(buf, new_mask, ATKBD_KEYMAP_SIZE);
if (err)
return err;
memcpy(atkbd->force_release_mask, new_mask, sizeof(atkbd->force_release_mask));
return count;
}
static ssize_t atkbd_show_scroll(struct atkbd *atkbd, char *buf)
{
return sprintf(buf, "%d\n", atkbd->scroll ? 1 : 0);

View file

@ -184,14 +184,13 @@ static int __devinit bfin_kpad_probe(struct platform_device *pdev)
int i, error;
if (!pdata->rows || !pdata->cols || !pdata->keymap) {
printk(KERN_ERR DRV_NAME
": No rows, cols or keymap from pdata\n");
dev_err(&pdev->dev, "no rows, cols or keymap from pdata\n");
return -EINVAL;
}
if (!pdata->keymapsize ||
pdata->keymapsize > (pdata->rows * pdata->cols)) {
printk(KERN_ERR DRV_NAME ": Invalid keymapsize\n");
dev_err(&pdev->dev, "invalid keymapsize\n");
return -EINVAL;
}
@ -211,8 +210,8 @@ static int __devinit bfin_kpad_probe(struct platform_device *pdev)
if (!pdata->debounce_time || pdata->debounce_time > MAX_MULT ||
!pdata->coldrive_time || pdata->coldrive_time > MAX_MULT) {
printk(KERN_WARNING DRV_NAME
": Invalid Debounce/Columndrive Time in platform data\n");
dev_warn(&pdev->dev,
"invalid platform debounce/columndrive time\n");
bfin_write_KPAD_MSEL(0xFF0); /* Default MSEL */
} else {
bfin_write_KPAD_MSEL(
@ -231,16 +230,14 @@ static int __devinit bfin_kpad_probe(struct platform_device *pdev)
if (peripheral_request_list((u16 *)&per_rows[MAX_RC - pdata->rows],
DRV_NAME)) {
printk(KERN_ERR DRV_NAME
": Requesting Peripherals failed\n");
dev_err(&pdev->dev, "requesting peripherals failed\n");
error = -EFAULT;
goto out0;
}
if (peripheral_request_list((u16 *)&per_cols[MAX_RC - pdata->cols],
DRV_NAME)) {
printk(KERN_ERR DRV_NAME
": Requesting Peripherals failed\n");
dev_err(&pdev->dev, "requesting peripherals failed\n");
error = -EFAULT;
goto out1;
}
@ -254,9 +251,8 @@ static int __devinit bfin_kpad_probe(struct platform_device *pdev)
error = request_irq(bf54x_kpad->irq, bfin_kpad_isr,
0, DRV_NAME, pdev);
if (error) {
printk(KERN_ERR DRV_NAME
": unable to claim irq %d; error %d\n",
bf54x_kpad->irq, error);
dev_err(&pdev->dev, "unable to claim irq %d\n",
bf54x_kpad->irq);
goto out2;
}
@ -297,8 +293,7 @@ static int __devinit bfin_kpad_probe(struct platform_device *pdev)
error = input_register_device(input);
if (error) {
printk(KERN_ERR DRV_NAME
": Unable to register input device (%d)\n", error);
dev_err(&pdev->dev, "unable to register input device\n");
goto out4;
}
@ -316,9 +311,6 @@ static int __devinit bfin_kpad_probe(struct platform_device *pdev)
device_init_wakeup(&pdev->dev, 1);
printk(KERN_ERR DRV_NAME
": Blackfin BF54x Keypad registered IRQ %d\n", bf54x_kpad->irq);
return 0;
out4:

View file

@ -216,8 +216,9 @@ static int __devexit gpio_keys_remove(struct platform_device *pdev)
#ifdef CONFIG_PM
static int gpio_keys_suspend(struct platform_device *pdev, pm_message_t state)
static int gpio_keys_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
int i;
@ -234,8 +235,9 @@ static int gpio_keys_suspend(struct platform_device *pdev, pm_message_t state)
return 0;
}
static int gpio_keys_resume(struct platform_device *pdev)
static int gpio_keys_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
int i;
@ -251,19 +253,22 @@ static int gpio_keys_resume(struct platform_device *pdev)
return 0;
}
#else
#define gpio_keys_suspend NULL
#define gpio_keys_resume NULL
static const struct dev_pm_ops gpio_keys_pm_ops = {
.suspend = gpio_keys_suspend,
.resume = gpio_keys_resume,
};
#endif
static struct platform_driver gpio_keys_device_driver = {
.probe = gpio_keys_probe,
.remove = __devexit_p(gpio_keys_remove),
.suspend = gpio_keys_suspend,
.resume = gpio_keys_resume,
.driver = {
.name = "gpio-keys",
.owner = THIS_MODULE,
#ifdef CONFIG_PM
.pm = &gpio_keys_pm_ops,
#endif
}
};

View file

@ -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);

View file

@ -525,12 +525,12 @@ lkkbd_event (struct input_dev *dev, unsigned int type, unsigned int code,
CHECK_LED (lk, leds_on, leds_off, LED_SCROLLL, LK_LED_SCROLLLOCK);
CHECK_LED (lk, leds_on, leds_off, LED_SLEEP, LK_LED_WAIT);
if (leds_on != 0) {
lk->serio->write (lk->serio, LK_CMD_LED_ON);
lk->serio->write (lk->serio, leds_on);
serio_write (lk->serio, LK_CMD_LED_ON);
serio_write (lk->serio, leds_on);
}
if (leds_off != 0) {
lk->serio->write (lk->serio, LK_CMD_LED_OFF);
lk->serio->write (lk->serio, leds_off);
serio_write (lk->serio, LK_CMD_LED_OFF);
serio_write (lk->serio, leds_off);
}
return 0;
@ -539,20 +539,20 @@ lkkbd_event (struct input_dev *dev, unsigned int type, unsigned int code,
case SND_CLICK:
if (value == 0) {
DBG ("%s: Deactivating key clicks\n", __func__);
lk->serio->write (lk->serio, LK_CMD_DISABLE_KEYCLICK);
lk->serio->write (lk->serio, LK_CMD_DISABLE_CTRCLICK);
serio_write (lk->serio, LK_CMD_DISABLE_KEYCLICK);
serio_write (lk->serio, LK_CMD_DISABLE_CTRCLICK);
} else {
DBG ("%s: Activating key clicks\n", __func__);
lk->serio->write (lk->serio, LK_CMD_ENABLE_KEYCLICK);
lk->serio->write (lk->serio, volume_to_hw (lk->keyclick_volume));
lk->serio->write (lk->serio, LK_CMD_ENABLE_CTRCLICK);
lk->serio->write (lk->serio, volume_to_hw (lk->ctrlclick_volume));
serio_write (lk->serio, LK_CMD_ENABLE_KEYCLICK);
serio_write (lk->serio, volume_to_hw (lk->keyclick_volume));
serio_write (lk->serio, LK_CMD_ENABLE_CTRCLICK);
serio_write (lk->serio, volume_to_hw (lk->ctrlclick_volume));
}
return 0;
case SND_BELL:
if (value != 0)
lk->serio->write (lk->serio, LK_CMD_SOUND_BELL);
serio_write (lk->serio, LK_CMD_SOUND_BELL);
return 0;
}
@ -579,10 +579,10 @@ lkkbd_reinit (struct work_struct *work)
unsigned char leds_off = 0;
/* Ask for ID */
lk->serio->write (lk->serio, LK_CMD_REQUEST_ID);
serio_write (lk->serio, LK_CMD_REQUEST_ID);
/* Reset parameters */
lk->serio->write (lk->serio, LK_CMD_SET_DEFAULTS);
serio_write (lk->serio, LK_CMD_SET_DEFAULTS);
/* Set LEDs */
CHECK_LED (lk, leds_on, leds_off, LED_CAPSL, LK_LED_SHIFTLOCK);
@ -590,12 +590,12 @@ lkkbd_reinit (struct work_struct *work)
CHECK_LED (lk, leds_on, leds_off, LED_SCROLLL, LK_LED_SCROLLLOCK);
CHECK_LED (lk, leds_on, leds_off, LED_SLEEP, LK_LED_WAIT);
if (leds_on != 0) {
lk->serio->write (lk->serio, LK_CMD_LED_ON);
lk->serio->write (lk->serio, leds_on);
serio_write (lk->serio, LK_CMD_LED_ON);
serio_write (lk->serio, leds_on);
}
if (leds_off != 0) {
lk->serio->write (lk->serio, LK_CMD_LED_OFF);
lk->serio->write (lk->serio, leds_off);
serio_write (lk->serio, LK_CMD_LED_OFF);
serio_write (lk->serio, leds_off);
}
/*
@ -603,31 +603,31 @@ lkkbd_reinit (struct work_struct *work)
* only work with a LK401 keyboard and grants access to
* LAlt, RAlt, RCompose and RShift.
*/
lk->serio->write (lk->serio, LK_CMD_ENABLE_LK401);
serio_write (lk->serio, LK_CMD_ENABLE_LK401);
/* Set all keys to UPDOWN mode */
for (division = 1; division <= 14; division++)
lk->serio->write (lk->serio, LK_CMD_SET_MODE (LK_MODE_UPDOWN,
serio_write (lk->serio, LK_CMD_SET_MODE (LK_MODE_UPDOWN,
division));
/* Enable bell and set volume */
lk->serio->write (lk->serio, LK_CMD_ENABLE_BELL);
lk->serio->write (lk->serio, volume_to_hw (lk->bell_volume));
serio_write (lk->serio, LK_CMD_ENABLE_BELL);
serio_write (lk->serio, volume_to_hw (lk->bell_volume));
/* Enable/disable keyclick (and possibly set volume) */
if (test_bit (SND_CLICK, lk->dev->snd)) {
lk->serio->write (lk->serio, LK_CMD_ENABLE_KEYCLICK);
lk->serio->write (lk->serio, volume_to_hw (lk->keyclick_volume));
lk->serio->write (lk->serio, LK_CMD_ENABLE_CTRCLICK);
lk->serio->write (lk->serio, volume_to_hw (lk->ctrlclick_volume));
serio_write (lk->serio, LK_CMD_ENABLE_KEYCLICK);
serio_write (lk->serio, volume_to_hw (lk->keyclick_volume));
serio_write (lk->serio, LK_CMD_ENABLE_CTRCLICK);
serio_write (lk->serio, volume_to_hw (lk->ctrlclick_volume));
} else {
lk->serio->write (lk->serio, LK_CMD_DISABLE_KEYCLICK);
lk->serio->write (lk->serio, LK_CMD_DISABLE_CTRCLICK);
serio_write (lk->serio, LK_CMD_DISABLE_KEYCLICK);
serio_write (lk->serio, LK_CMD_DISABLE_CTRCLICK);
}
/* Sound the bell if needed */
if (test_bit (SND_BELL, lk->dev->snd))
lk->serio->write (lk->serio, LK_CMD_SOUND_BELL);
serio_write (lk->serio, LK_CMD_SOUND_BELL);
}
/*
@ -684,8 +684,10 @@ lkkbd_connect (struct serio *serio, struct serio_driver *drv)
input_dev->keycode = lk->keycode;
input_dev->keycodesize = sizeof (lk_keycode_t);
input_dev->keycodemax = LK_NUM_KEYCODES;
for (i = 0; i < LK_NUM_KEYCODES; i++)
set_bit (lk->keycode[i], input_dev->keybit);
__set_bit (lk->keycode[i], input_dev->keybit);
__clear_bit(KEY_RESERVED, input_dev->keybit);
serio_set_drvdata (serio, lk);
@ -697,7 +699,7 @@ lkkbd_connect (struct serio *serio, struct serio_driver *drv)
if (err)
goto fail3;
lk->serio->write (lk->serio, LK_CMD_POWERCYCLE_RESET);
serio_write (lk->serio, LK_CMD_POWERCYCLE_RESET);
return 0;

View file

@ -319,7 +319,6 @@ static int __devinit matrix_keypad_probe(struct platform_device *pdev)
struct input_dev *input_dev;
unsigned short *keycodes;
unsigned int row_shift;
int i;
int err;
pdata = pdev->dev.platform_data;
@ -363,18 +362,10 @@ static int __devinit matrix_keypad_probe(struct platform_device *pdev)
input_dev->keycode = keycodes;
input_dev->keycodesize = sizeof(*keycodes);
input_dev->keycodemax = pdata->num_row_gpios << keypad->row_shift;
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);

View file

@ -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
},
};

View file

@ -128,7 +128,7 @@ static int __devinit sh_keysc_probe(struct platform_device *pdev)
struct resource *res;
struct input_dev *input;
char clk_name[8];
int i, k;
int i;
int irq, error;
if (!pdev->dev.platform_data) {
@ -195,17 +195,19 @@ static int __devinit sh_keysc_probe(struct platform_device *pdev)
input->id.product = 0x0001;
input->id.version = 0x0100;
input->keycode = pdata->keycodes;
input->keycodesize = sizeof(pdata->keycodes[0]);
input->keycodemax = ARRAY_SIZE(pdata->keycodes);
error = request_irq(irq, sh_keysc_isr, 0, pdev->name, pdev);
if (error) {
dev_err(&pdev->dev, "failed to request IRQ\n");
goto err4;
}
for (i = 0; i < SH_KEYSC_MAXKEYS; i++) {
k = pdata->keycodes[i];
if (k)
input_set_capability(input, EV_KEY, k);
}
for (i = 0; i < SH_KEYSC_MAXKEYS; i++)
__set_bit(pdata->keycodes[i], input->keybit);
__clear_bit(KEY_RESERVED, input->keybit);
error = input_register_device(input);
if (error) {
@ -221,7 +223,9 @@ static int __devinit sh_keysc_probe(struct platform_device *pdev)
iowrite16(KYCR2_IRQ_LEVEL, priv->iomem_base + KYCR2_OFFS);
device_init_wakeup(&pdev->dev, 1);
return 0;
err5:
free_irq(irq, pdev);
err4:
@ -252,6 +256,7 @@ static int __devexit sh_keysc_remove(struct platform_device *pdev)
platform_set_drvdata(pdev, NULL);
kfree(priv);
return 0;
}
@ -267,11 +272,12 @@ static int sh_keysc_suspend(struct device *dev)
if (device_may_wakeup(dev)) {
value |= 0x80;
enable_irq_wake(irq);
}
else
} else {
value &= ~0x80;
}
iowrite16(value, priv->iomem_base + KYCR1_OFFS);
return 0;
}

View file

@ -73,7 +73,7 @@ static unsigned char sunkbd_keycode[128] = {
*/
struct sunkbd {
unsigned char keycode[128];
unsigned char keycode[ARRAY_SIZE(sunkbd_keycode)];
struct input_dev *dev;
struct serio *serio;
struct work_struct tq;
@ -81,7 +81,7 @@ struct sunkbd {
char name[64];
char phys[32];
char type;
unsigned char enabled;
bool enabled;
volatile s8 reset;
volatile s8 layout;
};
@ -94,10 +94,14 @@ struct sunkbd {
static irqreturn_t sunkbd_interrupt(struct serio *serio,
unsigned char data, unsigned int flags)
{
struct 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);

View file

@ -31,7 +31,7 @@
#define KB_DISCHARGE_DELAY 10
#define KB_ACTIVATE_DELAY 10
static unsigned int tosakbd_keycode[NR_SCANCODES] = {
static unsigned short tosakbd_keycode[NR_SCANCODES] = {
0,
0, KEY_W, 0, 0, 0, KEY_K, KEY_BACKSPACE, KEY_P,
0, 0, 0, 0, 0, 0, 0, 0,
@ -50,9 +50,9 @@ KEY_X, KEY_F, KEY_SPACE, KEY_APOSTROPHE, TOSA_KEY_MAIL, KEY_LEFT, KEY_DOWN, KEY_
};
struct tosakbd {
unsigned int keycode[ARRAY_SIZE(tosakbd_keycode)];
unsigned short keycode[ARRAY_SIZE(tosakbd_keycode)];
struct input_dev *input;
int suspended;
bool suspended;
spinlock_t lock; /* protect kbd scanning */
struct timer_list timer;
};
@ -215,7 +215,7 @@ static int tosakbd_suspend(struct platform_device *dev, pm_message_t state)
unsigned long flags;
spin_lock_irqsave(&tosakbd->lock, flags);
tosakbd->suspended = 1;
tosakbd->suspended = true;
spin_unlock_irqrestore(&tosakbd->lock, flags);
del_timer_sync(&tosakbd->timer);
@ -227,7 +227,7 @@ static int tosakbd_resume(struct platform_device *dev)
{
struct tosakbd *tosakbd = platform_get_drvdata(dev);
tosakbd->suspended = 0;
tosakbd->suspended = false;
tosakbd_scankeyboard(dev);
return 0;
@ -277,14 +277,14 @@ static int __devinit tosakbd_probe(struct platform_device *pdev) {
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
input_dev->keycode = tosakbd->keycode;
input_dev->keycodesize = sizeof(unsigned int);
input_dev->keycodesize = sizeof(tosakbd->keycode[0]);
input_dev->keycodemax = ARRAY_SIZE(tosakbd_keycode);
memcpy(tosakbd->keycode, tosakbd_keycode, sizeof(tosakbd_keycode));
for (i = 0; i < ARRAY_SIZE(tosakbd_keycode); i++)
__set_bit(tosakbd->keycode[i], input_dev->keybit);
clear_bit(0, input_dev->keybit);
__clear_bit(KEY_RESERVED, input_dev->keybit);
/* Setup sense interrupts - RisingEdge Detect, sense lines as inputs */
for (i = 0; i < TOSA_KEY_SENSE_NUM; i++) {
@ -344,7 +344,7 @@ static int __devinit tosakbd_probe(struct platform_device *pdev) {
" direction for GPIO %d, error %d\n",
gpio, error);
gpio_free(gpio);
goto fail;
goto fail2;
}
}
@ -353,7 +353,7 @@ static int __devinit tosakbd_probe(struct platform_device *pdev) {
if (error) {
printk(KERN_ERR "tosakbd: Unable to register input device, "
"error: %d\n", error);
goto fail;
goto fail2;
}
printk(KERN_INFO "input: Tosa Keyboard Registered\n");

View 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, &reg, KEYP_ISR1, 1);
/* Release all keys if I2C has gone bad or
* the KEYP has gone to idle state */
if (ret >= 0 && (reg & KEYP_IMR1_KP))
twl4030_kp_scan(kp, false);
else
twl4030_kp_scan(kp, true);
return IRQ_HANDLED;
}
static int __devinit twl4030_kp_program(struct twl4030_keypad *kp)
{
u8 reg;
int i;
/* Enable controller, with hardware decoding but not autorepeat */
reg = KEYP_CTRL_SOFT_NRST | KEYP_CTRL_SOFTMODEN
| KEYP_CTRL_TOE_EN | KEYP_CTRL_KBD_ON;
if (twl4030_kpwrite_u8(kp, reg, KEYP_CTRL) < 0)
return -EIO;
/* NOTE: we could use sih_setup() here to package keypad
* event sources as four different IRQs ... but we don't.
*/
/* Enable TO rising and KP rising and falling edge detection */
reg = KEYP_EDR_KP_BOTH | KEYP_EDR_TO_RISING;
if (twl4030_kpwrite_u8(kp, reg, KEYP_EDR) < 0)
return -EIO;
/* Set PTV prescaler Field */
reg = (PTV_PRESCALER << KEYP_LK_PTV_PTV_SHIFT);
if (twl4030_kpwrite_u8(kp, reg, KEYP_LK_PTV) < 0)
return -EIO;
/* Set key debounce time to 20 ms */
i = KEYP_PERIOD_US(20000, PTV_PRESCALER);
if (twl4030_kpwrite_u8(kp, i, KEYP_DEB) < 0)
return -EIO;
/* Set timeout period to 100 ms */
i = KEYP_PERIOD_US(200000, PTV_PRESCALER);
if (twl4030_kpwrite_u8(kp, (i & 0xFF), KEYP_TIMEOUT_L) < 0)
return -EIO;
if (twl4030_kpwrite_u8(kp, (i >> 8), KEYP_TIMEOUT_H) < 0)
return -EIO;
/*
* Enable Clear-on-Read; disable remembering events that fire
* after the IRQ but before our handler acks (reads) them,
*/
reg = TWL4030_SIH_CTRL_COR_MASK | TWL4030_SIH_CTRL_PENDDIS_MASK;
if (twl4030_kpwrite_u8(kp, reg, KEYP_SIH_CTRL) < 0)
return -EIO;
/* initialize key state; irqs update it from here on */
if (twl4030_read_kp_matrix_state(kp, kp->kp_state) < 0)
return -EIO;
return 0;
}
/*
* Registers keypad device with input subsystem
* and configures TWL4030 keypad registers
*/
static int __devinit twl4030_kp_probe(struct platform_device *pdev)
{
struct twl4030_keypad_data *pdata = pdev->dev.platform_data;
const struct matrix_keymap_data *keymap_data = pdata->keymap_data;
struct twl4030_keypad *kp;
struct input_dev *input;
u8 reg;
int error;
if (!pdata || !pdata->rows || !pdata->cols ||
pdata->rows > TWL4030_MAX_ROWS || pdata->cols > TWL4030_MAX_COLS) {
dev_err(&pdev->dev, "Invalid platform_data\n");
return -EINVAL;
}
kp = kzalloc(sizeof(*kp), GFP_KERNEL);
input = input_allocate_device();
if (!kp || !input) {
error = -ENOMEM;
goto err1;
}
/* Get the debug Device */
kp->dbg_dev = &pdev->dev;
kp->input = input;
kp->n_rows = pdata->rows;
kp->n_cols = pdata->cols;
kp->irq = platform_get_irq(pdev, 0);
/* setup input device */
__set_bit(EV_KEY, input->evbit);
/* Enable auto repeat feature of Linux input subsystem */
if (pdata->rep)
__set_bit(EV_REP, input->evbit);
input_set_capability(input, EV_MSC, MSC_SCAN);
input->name = "TWL4030 Keypad";
input->phys = "twl4030_keypad/input0";
input->dev.parent = &pdev->dev;
input->id.bustype = BUS_HOST;
input->id.vendor = 0x0001;
input->id.product = 0x0001;
input->id.version = 0x0003;
input->keycode = kp->keymap;
input->keycodesize = sizeof(kp->keymap[0]);
input->keycodemax = ARRAY_SIZE(kp->keymap);
matrix_keypad_build_keymap(keymap_data, TWL4030_ROW_SHIFT,
input->keycode, input->keybit);
error = input_register_device(input);
if (error) {
dev_err(kp->dbg_dev,
"Unable to register twl4030 keypad device\n");
goto err1;
}
error = twl4030_kp_program(kp);
if (error)
goto err2;
/*
* This ISR will always execute in kernel thread context because of
* the need to access the TWL4030 over the I2C bus.
*
* NOTE: we assume this host is wired to TWL4040 INT1, not INT2 ...
*/
error = request_irq(kp->irq, do_kp_irq, 0, pdev->name, kp);
if (error) {
dev_info(kp->dbg_dev, "request_irq failed for irq no=%d\n",
kp->irq);
goto err3;
}
/* Enable KP and TO interrupts now. */
reg = (u8) ~(KEYP_IMR1_KP | KEYP_IMR1_TO);
if (twl4030_kpwrite_u8(kp, reg, KEYP_IMR1)) {
error = -EIO;
goto err4;
}
platform_set_drvdata(pdev, kp);
return 0;
err4:
/* mask all events - we don't care about the result */
(void) twl4030_kpwrite_u8(kp, 0xff, KEYP_IMR1);
err3:
free_irq(kp->irq, NULL);
err2:
input_unregister_device(input);
input = NULL;
err1:
input_free_device(input);
kfree(kp);
return error;
}
static int __devexit twl4030_kp_remove(struct platform_device *pdev)
{
struct twl4030_keypad *kp = platform_get_drvdata(pdev);
free_irq(kp->irq, kp);
input_unregister_device(kp->input);
platform_set_drvdata(pdev, NULL);
kfree(kp);
return 0;
}
/*
* NOTE: twl4030 are multi-function devices connected via I2C.
* So this device is a child of an I2C parent, thus it needs to
* support unplug/replug (which most platform devices don't).
*/
static struct platform_driver twl4030_kp_driver = {
.probe = twl4030_kp_probe,
.remove = __devexit_p(twl4030_kp_remove),
.driver = {
.name = "twl4030_keypad",
.owner = THIS_MODULE,
},
};
static int __init twl4030_kp_init(void)
{
return platform_driver_register(&twl4030_kp_driver);
}
module_init(twl4030_kp_init);
static void __exit twl4030_kp_exit(void)
{
platform_driver_unregister(&twl4030_kp_driver);
}
module_exit(twl4030_kp_exit);
MODULE_AUTHOR("Texas Instruments");
MODULE_DESCRIPTION("TWL4030 Keypad Driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:twl4030_keypad");

View 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");

View file

@ -269,4 +269,14 @@ config INPUT_DM355EVM
To compile this driver as a module, choose M here: the
module will be called dm355evm_keys.
config INPUT_BFIN_ROTARY
tristate "Blackfin Rotary support"
depends on BF54x || BF52x
help
Say Y here if you want to use the Blackfin Rotary.
To compile this driver as a module, choose M here: the
module will be called bfin-rotary.
endif

View file

@ -8,6 +8,7 @@ obj-$(CONFIG_INPUT_APANEL) += apanel.o
obj-$(CONFIG_INPUT_ATI_REMOTE) += ati_remote.o
obj-$(CONFIG_INPUT_ATI_REMOTE2) += ati_remote2.o
obj-$(CONFIG_INPUT_ATLAS_BTNS) += atlas_btns.o
obj-$(CONFIG_INPUT_BFIN_ROTARY) += bfin_rotary.o
obj-$(CONFIG_INPUT_CM109) += cm109.o
obj-$(CONFIG_INPUT_COBALT_BTNS) += cobalt_btns.o
obj-$(CONFIG_INPUT_DM355EVM) += dm355evm_keys.o

View 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");

View file

@ -116,7 +116,7 @@ static int __devinit cobalt_buttons_probe(struct platform_device *pdev)
}
bdev->poll_dev = poll_dev;
bdev->reg = ioremap(res->start, res->end - res->start + 1);
bdev->reg = ioremap(res->start, resource_size(res));
dev_set_drvdata(&pdev->dev, bdev);
error = input_register_polled_device(poll_dev);

View file

@ -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;

View file

@ -243,9 +243,9 @@ enum { KE_END, KE_KEY, KE_SW, KE_WIFI, KE_BLUETOOTH };
#define FE_UNTESTED 0x80
static struct key_entry *keymap; /* = NULL; Current key map */
static int have_wifi;
static int have_bluetooth;
static int have_leds;
static bool have_wifi;
static bool have_bluetooth;
static int leds_present; /* bitmask of leds present */
static int __init dmi_matched(const struct dmi_system_id *dmi)
{
@ -254,11 +254,11 @@ static int __init dmi_matched(const struct dmi_system_id *dmi)
keymap = dmi->driver_data;
for (key = keymap; key->type != KE_END; key++) {
if (key->type == KE_WIFI)
have_wifi = 1;
have_wifi = true;
else if (key->type == KE_BLUETOOTH)
have_bluetooth = 1;
have_bluetooth = true;
}
have_leds = key->code & (FE_MAIL_LED | FE_WIFI_LED);
leds_present = key->code & (FE_MAIL_LED | FE_WIFI_LED);
return 1;
}
@ -611,10 +611,24 @@ static struct key_entry keymap_wistron_generic[] __initdata = {
{ KE_END, 0 }
};
static struct key_entry keymap_aopen_1557[] __initdata = {
{ KE_KEY, 0x01, {KEY_HELP} },
{ KE_KEY, 0x11, {KEY_PROG1} },
{ KE_KEY, 0x12, {KEY_PROG2} },
{ KE_WIFI, 0x30 },
{ KE_KEY, 0x22, {KEY_REWIND} },
{ KE_KEY, 0x23, {KEY_FORWARD} },
{ KE_KEY, 0x24, {KEY_PLAYPAUSE} },
{ KE_KEY, 0x25, {KEY_STOPCD} },
{ KE_KEY, 0x31, {KEY_MAIL} },
{ KE_KEY, 0x36, {KEY_WWW} },
{ KE_END, 0 }
};
static struct key_entry keymap_prestigio[] __initdata = {
{ KE_KEY, 0x11, {KEY_PROG1} },
{ KE_KEY, 0x12, {KEY_PROG2} },
{ KE_WIFI, 0x30 },
{ KE_WIFI, 0x30 },
{ KE_KEY, 0x22, {KEY_REWIND} },
{ KE_KEY, 0x23, {KEY_FORWARD} },
{ KE_KEY, 0x24, {KEY_PLAYPAUSE} },
@ -985,6 +999,8 @@ static int __init select_keymap(void)
if (keymap_name != NULL) {
if (strcmp (keymap_name, "1557/MS2141") == 0)
keymap = keymap_wistron_ms2141;
else if (strcmp (keymap_name, "aopen1557") == 0)
keymap = keymap_aopen_1557;
else if (strcmp (keymap_name, "prestigio") == 0)
keymap = keymap_prestigio;
else if (strcmp (keymap_name, "generic") == 0)
@ -1009,8 +1025,8 @@ static int __init select_keymap(void)
static struct input_polled_dev *wistron_idev;
static unsigned long jiffies_last_press;
static int wifi_enabled;
static int bluetooth_enabled;
static bool wifi_enabled;
static bool bluetooth_enabled;
static void report_key(struct input_dev *dev, unsigned int keycode)
{
@ -1053,24 +1069,24 @@ static struct led_classdev wistron_wifi_led = {
static void __devinit wistron_led_init(struct device *parent)
{
if (have_leds & FE_WIFI_LED) {
if (leds_present & FE_WIFI_LED) {
u16 wifi = bios_get_default_setting(WIFI);
if (wifi & 1) {
wistron_wifi_led.brightness = (wifi & 2) ? LED_FULL : LED_OFF;
if (led_classdev_register(parent, &wistron_wifi_led))
have_leds &= ~FE_WIFI_LED;
leds_present &= ~FE_WIFI_LED;
else
bios_set_state(WIFI, wistron_wifi_led.brightness);
} else
have_leds &= ~FE_WIFI_LED;
leds_present &= ~FE_WIFI_LED;
}
if (have_leds & FE_MAIL_LED) {
if (leds_present & FE_MAIL_LED) {
/* bios_get_default_setting(MAIL) always retuns 0, so just turn the led off */
wistron_mail_led.brightness = LED_OFF;
if (led_classdev_register(parent, &wistron_mail_led))
have_leds &= ~FE_MAIL_LED;
leds_present &= ~FE_MAIL_LED;
else
bios_set_state(MAIL_LED, wistron_mail_led.brightness);
}
@ -1078,28 +1094,28 @@ static void __devinit wistron_led_init(struct device *parent)
static void __devexit wistron_led_remove(void)
{
if (have_leds & FE_MAIL_LED)
if (leds_present & FE_MAIL_LED)
led_classdev_unregister(&wistron_mail_led);
if (have_leds & FE_WIFI_LED)
if (leds_present & FE_WIFI_LED)
led_classdev_unregister(&wistron_wifi_led);
}
static inline void wistron_led_suspend(void)
{
if (have_leds & FE_MAIL_LED)
if (leds_present & FE_MAIL_LED)
led_classdev_suspend(&wistron_mail_led);
if (have_leds & FE_WIFI_LED)
if (leds_present & FE_WIFI_LED)
led_classdev_suspend(&wistron_wifi_led);
}
static inline void wistron_led_resume(void)
{
if (have_leds & FE_MAIL_LED)
if (leds_present & FE_MAIL_LED)
led_classdev_resume(&wistron_mail_led);
if (have_leds & FE_WIFI_LED)
if (leds_present & FE_WIFI_LED)
led_classdev_resume(&wistron_wifi_led);
}
@ -1312,7 +1328,7 @@ static int __devinit wistron_probe(struct platform_device *dev)
if (have_wifi) {
u16 wifi = bios_get_default_setting(WIFI);
if (wifi & 1)
wifi_enabled = (wifi & 2) ? 1 : 0;
wifi_enabled = wifi & 2;
else
have_wifi = 0;
@ -1323,15 +1339,16 @@ static int __devinit wistron_probe(struct platform_device *dev)
if (have_bluetooth) {
u16 bt = bios_get_default_setting(BLUETOOTH);
if (bt & 1)
bluetooth_enabled = (bt & 2) ? 1 : 0;
bluetooth_enabled = bt & 2;
else
have_bluetooth = 0;
have_bluetooth = false;
if (have_bluetooth)
bios_set_state(BLUETOOTH, bluetooth_enabled);
}
wistron_led_init(&dev->dev);
err = setup_input_dev();
if (err) {
bios_detach();
@ -1352,7 +1369,7 @@ static int __devexit wistron_remove(struct platform_device *dev)
}
#ifdef CONFIG_PM
static int wistron_suspend(struct platform_device *dev, pm_message_t state)
static int wistron_suspend(struct device *dev)
{
if (have_wifi)
bios_set_state(WIFI, 0);
@ -1361,10 +1378,11 @@ static int wistron_suspend(struct platform_device *dev, pm_message_t state)
bios_set_state(BLUETOOTH, 0);
wistron_led_suspend();
return 0;
}
static int wistron_resume(struct platform_device *dev)
static int wistron_resume(struct device *dev)
{
if (have_wifi)
bios_set_state(WIFI, wifi_enabled);
@ -1373,24 +1391,30 @@ static int wistron_resume(struct platform_device *dev)
bios_set_state(BLUETOOTH, bluetooth_enabled);
wistron_led_resume();
poll_bios(true);
return 0;
}
#else
#define wistron_suspend NULL
#define wistron_resume NULL
static const struct dev_pm_ops wistron_pm_ops = {
.suspend = wistron_suspend,
.resume = wistron_resume,
.poweroff = wistron_suspend,
.restore = wistron_resume,
};
#endif
static struct platform_driver wistron_driver = {
.driver = {
.name = "wistron-bios",
.owner = THIS_MODULE,
#if CONFIG_PM
.pm = &wistron_pm_ops,
#endif
},
.probe = wistron_probe,
.remove = __devexit_p(wistron_remove),
.suspend = wistron_suspend,
.resume = wistron_resume,
};
static int __init wb_module_init(void)

View file

@ -107,6 +107,14 @@ config MOUSE_PS2_ELANTECH
entries. For further information,
see <file:Documentation/input/elantech.txt>.
config MOUSE_PS2_SENTELIC
bool "Sentelic Finger Sensing Pad PS/2 protocol extension"
depends on MOUSE_PS2
help
Say Y here if you have a laptop (such as MSI WIND Netbook)
with Sentelic Finger Sensing Pad touchpad.
If unsure, say N.
config MOUSE_PS2_TOUCHKIT
bool "eGalax TouchKit PS/2 protocol extension"
@ -262,14 +270,6 @@ config MOUSE_VSXXXAA
described in the source file). This driver also works with the
digitizer (VSXXX-AB) DEC produced.
config MOUSE_HIL
tristate "HIL pointers (mice etc)."
depends on GSC || HP300
select HP_SDC
select HIL_MLC
help
Say Y here to support HIL pointers.
config MOUSE_GPIO
tristate "GPIO mouse"
depends on GENERIC_GPIO

View file

@ -9,7 +9,6 @@ obj-$(CONFIG_MOUSE_APPLETOUCH) += appletouch.o
obj-$(CONFIG_MOUSE_ATARI) += atarimouse.o
obj-$(CONFIG_MOUSE_BCM5974) += bcm5974.o
obj-$(CONFIG_MOUSE_GPIO) += gpio_mouse.o
obj-$(CONFIG_MOUSE_HIL) += hil_ptr.o
obj-$(CONFIG_MOUSE_INPORT) += inport.o
obj-$(CONFIG_MOUSE_LOGIBM) += logibm.o
obj-$(CONFIG_MOUSE_MAPLE) += maplemouse.o
@ -28,5 +27,6 @@ psmouse-$(CONFIG_MOUSE_PS2_ELANTECH) += elantech.o
psmouse-$(CONFIG_MOUSE_PS2_OLPC) += hgpk.o
psmouse-$(CONFIG_MOUSE_PS2_LOGIPS2PP) += logips2pp.o
psmouse-$(CONFIG_MOUSE_PS2_LIFEBOOK) += lifebook.o
psmouse-$(CONFIG_MOUSE_PS2_SENTELIC) += sentelic.o
psmouse-$(CONFIG_MOUSE_PS2_TRACKPOINT) += trackpoint.o
psmouse-$(CONFIG_MOUSE_PS2_TOUCHKIT) += touchkit_ps2.o

View file

@ -279,7 +279,7 @@ static const struct alps_model_info *alps_get_model(struct psmouse *psmouse, int
* subsequent commands. It looks like glidepad is behind stickpointer,
* I'd thought it would be other way around...
*/
static int alps_passthrough_mode(struct psmouse *psmouse, int enable)
static int alps_passthrough_mode(struct psmouse *psmouse, bool enable)
{
struct ps2dev *ps2dev = &psmouse->ps2dev;
int cmd = enable ? PSMOUSE_CMD_SETSCALE21 : PSMOUSE_CMD_SETSCALE11;
@ -367,16 +367,16 @@ static int alps_poll(struct psmouse *psmouse)
{
struct alps_data *priv = psmouse->private;
unsigned char buf[6];
int poll_failed;
bool poll_failed;
if (priv->i->flags & ALPS_PASS)
alps_passthrough_mode(psmouse, 1);
alps_passthrough_mode(psmouse, true);
poll_failed = ps2_command(&psmouse->ps2dev, buf,
PSMOUSE_CMD_POLL | (psmouse->pktsize << 8)) < 0;
if (priv->i->flags & ALPS_PASS)
alps_passthrough_mode(psmouse, 0);
alps_passthrough_mode(psmouse, false);
if (poll_failed || (buf[0] & priv->i->mask0) != priv->i->byte0)
return -1;
@ -401,10 +401,12 @@ static int alps_hw_init(struct psmouse *psmouse, int *version)
if (!priv->i)
return -1;
if ((priv->i->flags & ALPS_PASS) && alps_passthrough_mode(psmouse, 1))
if ((priv->i->flags & ALPS_PASS) &&
alps_passthrough_mode(psmouse, true)) {
return -1;
}
if (alps_tap_mode(psmouse, 1)) {
if (alps_tap_mode(psmouse, true)) {
printk(KERN_WARNING "alps.c: Failed to enable hardware tapping\n");
return -1;
}
@ -414,8 +416,10 @@ static int alps_hw_init(struct psmouse *psmouse, int *version)
return -1;
}
if ((priv->i->flags & ALPS_PASS) && alps_passthrough_mode(psmouse, 0))
if ((priv->i->flags & ALPS_PASS) &&
alps_passthrough_mode(psmouse, false)) {
return -1;
}
/* ALPS needs stream mode, otherwise it won't report any data */
if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETSTREAM)) {
@ -519,7 +523,7 @@ 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;

View file

@ -26,10 +26,10 @@ struct alps_data {
};
#ifdef CONFIG_MOUSE_PS2_ALPS
int alps_detect(struct psmouse *psmouse, int set_properties);
int alps_detect(struct psmouse *psmouse, bool set_properties);
int alps_init(struct psmouse *psmouse);
#else
inline int alps_detect(struct psmouse *psmouse, int set_properties)
inline int alps_detect(struct psmouse *psmouse, bool set_properties)
{
return -ENOSYS;
}

View file

@ -317,7 +317,7 @@ static int report_tp_state(struct bcm5974 *dev, int size)
const struct tp_finger *f;
struct input_dev *input = dev->input;
int raw_p, raw_w, raw_x, raw_y, raw_n;
int ptest = 0, origin = 0, ibt = 0, nmin = 0, nmax = 0;
int ptest, origin, ibt = 0, nmin = 0, nmax = 0;
int abs_p = 0, abs_w = 0, abs_x = 0, abs_y = 0;
if (size < c->tp_offset || (size - c->tp_offset) % SIZEOF_FINGER != 0)
@ -345,21 +345,22 @@ static int report_tp_state(struct bcm5974 *dev, int size)
/* set the integrated button if applicable */
if (c->tp_type == TYPE2)
ibt = raw2int(dev->tp_data[BUTTON_TYPE2]);
}
/* while tracking finger still valid, count all fingers */
if (ptest > PRESSURE_LOW && origin) {
abs_p = ptest;
abs_w = int2bound(&c->w, raw_w);
abs_x = int2bound(&c->x, raw_x - c->x.devmin);
abs_y = int2bound(&c->y, c->y.devmax - raw_y);
while (raw_n--) {
ptest = int2bound(&c->p, raw2int(f->force_major));
if (ptest > PRESSURE_LOW)
nmax++;
if (ptest > PRESSURE_HIGH)
nmin++;
f++;
/* while tracking finger still valid, count all fingers */
if (ptest > PRESSURE_LOW && origin) {
abs_p = ptest;
abs_w = int2bound(&c->w, raw_w);
abs_x = int2bound(&c->x, raw_x - c->x.devmin);
abs_y = int2bound(&c->y, c->y.devmax - raw_y);
while (raw_n--) {
ptest = int2bound(&c->p,
raw2int(f->force_major));
if (ptest > PRESSURE_LOW)
nmax++;
if (ptest > PRESSURE_HIGH)
nmin++;
f++;
}
}
}

View file

@ -553,7 +553,7 @@ static struct attribute_group elantech_attr_group = {
/*
* Use magic knock to detect Elantech touchpad
*/
int elantech_detect(struct psmouse *psmouse, int set_properties)
int elantech_detect(struct psmouse *psmouse, bool set_properties)
{
struct ps2dev *ps2dev = &psmouse->ps2dev;
unsigned char param[3];

View file

@ -109,10 +109,10 @@ struct elantech_data {
};
#ifdef CONFIG_MOUSE_PS2_ELANTECH
int elantech_detect(struct psmouse *psmouse, int set_properties);
int elantech_detect(struct psmouse *psmouse, bool set_properties);
int elantech_init(struct psmouse *psmouse);
#else
static inline int elantech_detect(struct psmouse *psmouse, int set_properties)
static inline int elantech_detect(struct psmouse *psmouse, bool set_properties)
{
return -ENOSYS;
}

View file

@ -367,7 +367,36 @@ static ssize_t hgpk_set_powered(struct psmouse *psmouse, void *data,
}
__PSMOUSE_DEFINE_ATTR(powered, S_IWUSR | S_IRUGO, NULL,
hgpk_show_powered, hgpk_set_powered, 0);
hgpk_show_powered, hgpk_set_powered, false);
static ssize_t hgpk_trigger_recal_show(struct psmouse *psmouse,
void *data, char *buf)
{
return -EINVAL;
}
static ssize_t hgpk_trigger_recal(struct psmouse *psmouse, void *data,
const char *buf, size_t count)
{
struct hgpk_data *priv = psmouse->private;
unsigned long value;
int err;
err = strict_strtoul(buf, 10, &value);
if (err || value != 1)
return -EINVAL;
/*
* We queue work instead of doing recalibration right here
* to avoid adding locking to to hgpk_force_recalibrate()
* since workqueue provides serialization.
*/
psmouse_queue_work(psmouse, &priv->recalib_wq, 0);
return count;
}
__PSMOUSE_DEFINE_ATTR(recalibrate, S_IWUSR | S_IRUGO, NULL,
hgpk_trigger_recal_show, hgpk_trigger_recal, false);
static void hgpk_disconnect(struct psmouse *psmouse)
{
@ -375,6 +404,11 @@ static void hgpk_disconnect(struct psmouse *psmouse)
device_remove_file(&psmouse->ps2dev.serio->dev,
&psmouse_attr_powered.dattr);
if (psmouse->model >= HGPK_MODEL_C)
device_remove_file(&psmouse->ps2dev.serio->dev,
&psmouse_attr_recalibrate.dattr);
psmouse_reset(psmouse);
kfree(priv);
}
@ -423,10 +457,25 @@ static int hgpk_register(struct psmouse *psmouse)
err = device_create_file(&psmouse->ps2dev.serio->dev,
&psmouse_attr_powered.dattr);
if (err)
hgpk_err(psmouse, "Failed to create sysfs attribute\n");
if (err) {
hgpk_err(psmouse, "Failed creating 'powered' sysfs node\n");
return err;
}
return err;
/* C-series touchpads added the recalibrate command */
if (psmouse->model >= HGPK_MODEL_C) {
err = device_create_file(&psmouse->ps2dev.serio->dev,
&psmouse_attr_recalibrate.dattr);
if (err) {
hgpk_err(psmouse,
"Failed creating 'recalibrate' sysfs node\n");
device_remove_file(&psmouse->ps2dev.serio->dev,
&psmouse_attr_powered.dattr);
return err;
}
}
return 0;
}
int hgpk_init(struct psmouse *psmouse)
@ -440,7 +489,7 @@ int hgpk_init(struct psmouse *psmouse)
psmouse->private = priv;
priv->psmouse = psmouse;
priv->powered = 1;
priv->powered = true;
INIT_DELAYED_WORK(&priv->recalib_wq, hgpk_recalib_work);
err = psmouse_reset(psmouse);
@ -483,7 +532,7 @@ static enum hgpk_model_t hgpk_get_model(struct psmouse *psmouse)
return param[2];
}
int hgpk_detect(struct psmouse *psmouse, int set_properties)
int hgpk_detect(struct psmouse *psmouse, bool set_properties)
{
int version;

View file

@ -15,7 +15,7 @@ enum hgpk_model_t {
struct hgpk_data {
struct psmouse *psmouse;
int powered;
bool powered;
int count, x_tally, y_tally; /* hardware workaround stuff */
unsigned long recalib_window;
struct delayed_work recalib_wq;
@ -33,10 +33,10 @@ struct hgpk_data {
dev_notice(&(psmouse)->ps2dev.serio->dev, format, ## arg)
#ifdef CONFIG_MOUSE_PS2_OLPC
int hgpk_detect(struct psmouse *psmouse, int set_properties);
int hgpk_detect(struct psmouse *psmouse, bool set_properties);
int hgpk_init(struct psmouse *psmouse);
#else
static inline int hgpk_detect(struct psmouse *psmouse, int set_properties)
static inline int hgpk_detect(struct psmouse *psmouse, bool set_properties)
{
return -ENODEV;
}

View file

@ -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);

View file

@ -33,11 +33,11 @@ static int lifebook_set_serio_phys(const struct dmi_system_id *d)
return 0;
}
static unsigned char lifebook_use_6byte_proto;
static bool lifebook_use_6byte_proto;
static int lifebook_set_6byte_proto(const struct dmi_system_id *d)
{
lifebook_use_6byte_proto = 1;
lifebook_use_6byte_proto = true;
return 0;
}
@ -125,7 +125,7 @@ static psmouse_ret_t lifebook_process_byte(struct psmouse *psmouse)
struct input_dev *dev1 = psmouse->dev;
struct input_dev *dev2 = priv ? priv->dev2 : NULL;
unsigned char *packet = psmouse->packet;
int relative_packet = packet[0] & 0x08;
bool relative_packet = packet[0] & 0x08;
if (relative_packet || !lifebook_use_6byte_proto) {
if (psmouse->pktcnt != 3)
@ -242,7 +242,7 @@ static void lifebook_disconnect(struct psmouse *psmouse)
psmouse->private = NULL;
}
int lifebook_detect(struct psmouse *psmouse, int set_properties)
int lifebook_detect(struct psmouse *psmouse, bool set_properties)
{
if (!dmi_check_system(lifebook_dmi_table))
return -1;

View file

@ -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;
}

View file

@ -130,14 +130,11 @@ static int ps2pp_cmd(struct psmouse *psmouse, unsigned char *param, unsigned cha
* 0 - disabled
*/
static void ps2pp_set_smartscroll(struct psmouse *psmouse, unsigned int smartscroll)
static void ps2pp_set_smartscroll(struct psmouse *psmouse, bool smartscroll)
{
struct ps2dev *ps2dev = &psmouse->ps2dev;
unsigned char param[4];
if (smartscroll > 1)
smartscroll = 1;
ps2pp_cmd(psmouse, param, 0x32);
param[0] = 0;
@ -149,12 +146,14 @@ static void ps2pp_set_smartscroll(struct psmouse *psmouse, unsigned int smartscr
ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
}
static ssize_t ps2pp_attr_show_smartscroll(struct psmouse *psmouse, void *data, char *buf)
static ssize_t ps2pp_attr_show_smartscroll(struct psmouse *psmouse,
void *data, char *buf)
{
return sprintf(buf, "%d\n", psmouse->smartscroll ? 1 : 0);
return sprintf(buf, "%d\n", psmouse->smartscroll);
}
static ssize_t ps2pp_attr_set_smartscroll(struct psmouse *psmouse, void *data, const char *buf, size_t count)
static ssize_t ps2pp_attr_set_smartscroll(struct psmouse *psmouse, void *data,
const char *buf, size_t count)
{
unsigned long value;
@ -261,29 +260,29 @@ static const struct ps2pp_info *get_model_info(unsigned char model)
static void ps2pp_set_model_properties(struct psmouse *psmouse,
const struct ps2pp_info *model_info,
int using_ps2pp)
bool using_ps2pp)
{
struct input_dev *input_dev = psmouse->dev;
if (model_info->features & PS2PP_SIDE_BTN)
set_bit(BTN_SIDE, input_dev->keybit);
__set_bit(BTN_SIDE, input_dev->keybit);
if (model_info->features & PS2PP_EXTRA_BTN)
set_bit(BTN_EXTRA, input_dev->keybit);
__set_bit(BTN_EXTRA, input_dev->keybit);
if (model_info->features & PS2PP_TASK_BTN)
set_bit(BTN_TASK, input_dev->keybit);
__set_bit(BTN_TASK, input_dev->keybit);
if (model_info->features & PS2PP_NAV_BTN) {
set_bit(BTN_FORWARD, input_dev->keybit);
set_bit(BTN_BACK, input_dev->keybit);
__set_bit(BTN_FORWARD, input_dev->keybit);
__set_bit(BTN_BACK, input_dev->keybit);
}
if (model_info->features & PS2PP_WHEEL)
set_bit(REL_WHEEL, input_dev->relbit);
__set_bit(REL_WHEEL, input_dev->relbit);
if (model_info->features & PS2PP_HWHEEL)
set_bit(REL_HWHEEL, input_dev->relbit);
__set_bit(REL_HWHEEL, input_dev->relbit);
switch (model_info->kind) {
case PS2PP_KIND_WHEEL:
@ -321,13 +320,13 @@ static void ps2pp_set_model_properties(struct psmouse *psmouse,
* that support it.
*/
int ps2pp_init(struct psmouse *psmouse, int set_properties)
int ps2pp_init(struct psmouse *psmouse, bool set_properties)
{
struct ps2dev *ps2dev = &psmouse->ps2dev;
unsigned char param[4];
unsigned char model, buttons;
const struct ps2pp_info *model_info;
int use_ps2pp = 0;
bool use_ps2pp = false;
int error;
param[0] = 0;
@ -364,7 +363,7 @@ int ps2pp_init(struct psmouse *psmouse, int set_properties)
param[0] = 0;
if (!ps2_command(ps2dev, param, 0x13d1) &&
param[0] == 0x06 && param[1] == 0x00 && param[2] == 0x14) {
use_ps2pp = 1;
use_ps2pp = true;
}
} else {
@ -376,8 +375,8 @@ int ps2pp_init(struct psmouse *psmouse, int set_properties)
if ((param[0] & 0x78) == 0x48 &&
(param[1] & 0xf3) == 0xc2 &&
(param[2] & 0x03) == ((param[1] >> 2) & 3)) {
ps2pp_set_smartscroll(psmouse, psmouse->smartscroll);
use_ps2pp = 1;
ps2pp_set_smartscroll(psmouse, false);
use_ps2pp = true;
}
}
}
@ -406,7 +405,7 @@ int ps2pp_init(struct psmouse *psmouse, int set_properties)
}
if (buttons < 3)
clear_bit(BTN_MIDDLE, psmouse->dev->keybit);
__clear_bit(BTN_MIDDLE, psmouse->dev->keybit);
if (model_info)
ps2pp_set_model_properties(psmouse, model_info, use_ps2pp);

View file

@ -12,9 +12,9 @@
#define _LOGIPS2PP_H
#ifdef CONFIG_MOUSE_PS2_LOGIPS2PP
int ps2pp_init(struct psmouse *psmouse, int set_properties);
int ps2pp_init(struct psmouse *psmouse, bool set_properties);
#else
inline int ps2pp_init(struct psmouse *psmouse, int set_properties)
inline int ps2pp_init(struct psmouse *psmouse, bool set_properties)
{
return -ENOSYS;
}

View file

@ -30,6 +30,7 @@
#include "trackpoint.h"
#include "touchkit_ps2.h"
#include "elantech.h"
#include "sentelic.h"
#define DRIVER_DESC "PS/2 mouse driver"
@ -108,10 +109,10 @@ static struct workqueue_struct *kpsmoused_wq;
struct psmouse_protocol {
enum psmouse_type type;
bool maxproto;
const char *name;
const char *alias;
int maxproto;
int (*detect)(struct psmouse *, int);
int (*detect)(struct psmouse *, bool);
int (*init)(struct psmouse *);
};
@ -216,7 +217,7 @@ void psmouse_queue_work(struct psmouse *psmouse, struct delayed_work *work,
static inline void __psmouse_set_state(struct psmouse *psmouse, enum psmouse_state new_state)
{
psmouse->state = new_state;
psmouse->pktcnt = psmouse->out_of_sync = 0;
psmouse->pktcnt = psmouse->out_of_sync_cnt = 0;
psmouse->ps2dev.flags = 0;
psmouse->last = jiffies;
}
@ -249,7 +250,7 @@ static int psmouse_handle_byte(struct psmouse *psmouse)
if (psmouse->state == PSMOUSE_ACTIVATED) {
printk(KERN_WARNING "psmouse.c: %s at %s lost sync at byte %d\n",
psmouse->name, psmouse->phys, psmouse->pktcnt);
if (++psmouse->out_of_sync == psmouse->resetafter) {
if (++psmouse->out_of_sync_cnt == psmouse->resetafter) {
__psmouse_set_state(psmouse, PSMOUSE_IGNORE);
printk(KERN_NOTICE "psmouse.c: issuing reconnect request\n");
serio_reconnect(psmouse->ps2dev.serio);
@ -261,8 +262,8 @@ static int psmouse_handle_byte(struct psmouse *psmouse)
case PSMOUSE_FULL_PACKET:
psmouse->pktcnt = 0;
if (psmouse->out_of_sync) {
psmouse->out_of_sync = 0;
if (psmouse->out_of_sync_cnt) {
psmouse->out_of_sync_cnt = 0;
printk(KERN_NOTICE "psmouse.c: %s at %s - driver resynched.\n",
psmouse->name, psmouse->phys);
}
@ -408,7 +409,7 @@ int psmouse_reset(struct psmouse *psmouse)
/*
* Genius NetMouse magic init.
*/
static int genius_detect(struct psmouse *psmouse, int set_properties)
static int genius_detect(struct psmouse *psmouse, bool set_properties)
{
struct ps2dev *ps2dev = &psmouse->ps2dev;
unsigned char param[4];
@ -424,9 +425,9 @@ static int genius_detect(struct psmouse *psmouse, int set_properties)
return -1;
if (set_properties) {
set_bit(BTN_EXTRA, psmouse->dev->keybit);
set_bit(BTN_SIDE, psmouse->dev->keybit);
set_bit(REL_WHEEL, psmouse->dev->relbit);
__set_bit(BTN_EXTRA, psmouse->dev->keybit);
__set_bit(BTN_SIDE, psmouse->dev->keybit);
__set_bit(REL_WHEEL, psmouse->dev->relbit);
psmouse->vendor = "Genius";
psmouse->name = "Mouse";
@ -439,7 +440,7 @@ static int genius_detect(struct psmouse *psmouse, int set_properties)
/*
* IntelliMouse magic init.
*/
static int intellimouse_detect(struct psmouse *psmouse, int set_properties)
static int intellimouse_detect(struct psmouse *psmouse, bool set_properties)
{
struct ps2dev *ps2dev = &psmouse->ps2dev;
unsigned char param[2];
@ -456,8 +457,8 @@ static int intellimouse_detect(struct psmouse *psmouse, int set_properties)
return -1;
if (set_properties) {
set_bit(BTN_MIDDLE, psmouse->dev->keybit);
set_bit(REL_WHEEL, psmouse->dev->relbit);
__set_bit(BTN_MIDDLE, psmouse->dev->keybit);
__set_bit(REL_WHEEL, psmouse->dev->relbit);
if (!psmouse->vendor) psmouse->vendor = "Generic";
if (!psmouse->name) psmouse->name = "Wheel Mouse";
@ -470,7 +471,7 @@ static int intellimouse_detect(struct psmouse *psmouse, int set_properties)
/*
* Try IntelliMouse/Explorer magic init.
*/
static int im_explorer_detect(struct psmouse *psmouse, int set_properties)
static int im_explorer_detect(struct psmouse *psmouse, bool set_properties)
{
struct ps2dev *ps2dev = &psmouse->ps2dev;
unsigned char param[2];
@ -497,11 +498,11 @@ static int im_explorer_detect(struct psmouse *psmouse, int set_properties)
ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
if (set_properties) {
set_bit(BTN_MIDDLE, psmouse->dev->keybit);
set_bit(REL_WHEEL, psmouse->dev->relbit);
set_bit(REL_HWHEEL, psmouse->dev->relbit);
set_bit(BTN_SIDE, psmouse->dev->keybit);
set_bit(BTN_EXTRA, psmouse->dev->keybit);
__set_bit(BTN_MIDDLE, psmouse->dev->keybit);
__set_bit(REL_WHEEL, psmouse->dev->relbit);
__set_bit(REL_HWHEEL, psmouse->dev->relbit);
__set_bit(BTN_SIDE, psmouse->dev->keybit);
__set_bit(BTN_EXTRA, psmouse->dev->keybit);
if (!psmouse->vendor) psmouse->vendor = "Generic";
if (!psmouse->name) psmouse->name = "Explorer Mouse";
@ -514,7 +515,7 @@ static int im_explorer_detect(struct psmouse *psmouse, int set_properties)
/*
* Kensington ThinkingMouse / ExpertMouse magic init.
*/
static int thinking_detect(struct psmouse *psmouse, int set_properties)
static int thinking_detect(struct psmouse *psmouse, bool set_properties)
{
struct ps2dev *ps2dev = &psmouse->ps2dev;
unsigned char param[2];
@ -535,7 +536,7 @@ static int thinking_detect(struct psmouse *psmouse, int set_properties)
return -1;
if (set_properties) {
set_bit(BTN_EXTRA, psmouse->dev->keybit);
__set_bit(BTN_EXTRA, psmouse->dev->keybit);
psmouse->vendor = "Kensington";
psmouse->name = "ThinkingMouse";
@ -547,7 +548,7 @@ static int thinking_detect(struct psmouse *psmouse, int set_properties)
/*
* Bare PS/2 protocol "detection". Always succeeds.
*/
static int ps2bare_detect(struct psmouse *psmouse, int set_properties)
static int ps2bare_detect(struct psmouse *psmouse, bool set_properties)
{
if (set_properties) {
if (!psmouse->vendor) psmouse->vendor = "Generic";
@ -561,12 +562,12 @@ static int ps2bare_detect(struct psmouse *psmouse, int set_properties)
* Cortron PS/2 protocol detection. There's no special way to detect it, so it
* must be forced by sysfs protocol writing.
*/
static int cortron_detect(struct psmouse *psmouse, int set_properties)
static int cortron_detect(struct psmouse *psmouse, bool set_properties)
{
if (set_properties) {
psmouse->vendor = "Cortron";
psmouse->name = "PS/2 Trackball";
set_bit(BTN_SIDE, psmouse->dev->keybit);
__set_bit(BTN_SIDE, psmouse->dev->keybit);
}
return 0;
@ -578,9 +579,9 @@ static int cortron_detect(struct psmouse *psmouse, int set_properties)
*/
static int psmouse_extensions(struct psmouse *psmouse,
unsigned int max_proto, int set_properties)
unsigned int max_proto, bool set_properties)
{
int synaptics_hardware = 0;
bool synaptics_hardware = true;
/*
* We always check for lifebook because it does not disturb mouse
@ -607,7 +608,7 @@ static int psmouse_extensions(struct psmouse *psmouse,
* can reset it properly after probing for intellimouse.
*/
if (max_proto > PSMOUSE_PS2 && synaptics_detect(psmouse, set_properties) == 0) {
synaptics_hardware = 1;
synaptics_hardware = true;
if (max_proto > PSMOUSE_IMEX) {
if (!set_properties || synaptics_init(psmouse) == 0)
@ -666,6 +667,20 @@ static int psmouse_extensions(struct psmouse *psmouse,
max_proto = PSMOUSE_IMEX;
}
/*
* Try Finger Sensing Pad
*/
if (max_proto > PSMOUSE_IMEX) {
if (fsp_detect(psmouse, set_properties) == 0) {
if (!set_properties || fsp_init(psmouse) == 0)
return PSMOUSE_FSP;
/*
* Init failed, try basic relative protocols
*/
max_proto = PSMOUSE_IMEX;
}
}
if (max_proto > PSMOUSE_IMEX) {
if (genius_detect(psmouse, set_properties) == 0)
return PSMOUSE_GENPS;
@ -718,7 +733,7 @@ static const struct psmouse_protocol psmouse_protocols[] = {
.type = PSMOUSE_PS2,
.name = "PS/2",
.alias = "bare",
.maxproto = 1,
.maxproto = true,
.detect = ps2bare_detect,
},
#ifdef CONFIG_MOUSE_PS2_LOGIPS2PP
@ -745,14 +760,14 @@ static const struct psmouse_protocol psmouse_protocols[] = {
.type = PSMOUSE_IMPS,
.name = "ImPS/2",
.alias = "imps",
.maxproto = 1,
.maxproto = true,
.detect = intellimouse_detect,
},
{
.type = PSMOUSE_IMEX,
.name = "ImExPS/2",
.alias = "exps",
.maxproto = 1,
.maxproto = true,
.detect = im_explorer_detect,
},
#ifdef CONFIG_MOUSE_PS2_SYNAPTICS
@ -813,7 +828,16 @@ static const struct psmouse_protocol psmouse_protocols[] = {
.detect = elantech_detect,
.init = elantech_init,
},
#endif
#endif
#ifdef CONFIG_MOUSE_PS2_SENTELIC
{
.type = PSMOUSE_FSP,
.name = "FSPPS/2",
.alias = "fsp",
.detect = fsp_detect,
.init = fsp_init,
},
#endif
{
.type = PSMOUSE_CORTRON,
.name = "CortronPS/2",
@ -824,7 +848,7 @@ static const struct psmouse_protocol psmouse_protocols[] = {
.type = PSMOUSE_AUTO,
.name = "auto",
.alias = "any",
.maxproto = 1,
.maxproto = true,
},
};
@ -990,7 +1014,7 @@ static void psmouse_resync(struct work_struct *work)
container_of(work, struct psmouse, resync_work.work);
struct serio *serio = psmouse->ps2dev.serio;
psmouse_ret_t rc = PSMOUSE_GOOD_DATA;
int failed = 0, enabled = 0;
bool failed = false, enabled = false;
int i;
mutex_lock(&psmouse_mutex);
@ -1017,9 +1041,9 @@ static void psmouse_resync(struct work_struct *work)
if (ps2_sendbyte(&psmouse->ps2dev, PSMOUSE_CMD_DISABLE, 20)) {
if (psmouse->num_resyncs < 3 || psmouse->acks_disable_command)
failed = 1;
failed = true;
} else
psmouse->acks_disable_command = 1;
psmouse->acks_disable_command = true;
/*
* Poll the mouse. If it was reset the packet will be shorter than
@ -1030,7 +1054,7 @@ static void psmouse_resync(struct work_struct *work)
*/
if (!failed) {
if (psmouse->poll(psmouse))
failed = 1;
failed = true;
else {
psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
for (i = 0; i < psmouse->pktsize; i++) {
@ -1040,7 +1064,7 @@ static void psmouse_resync(struct work_struct *work)
break;
}
if (rc != PSMOUSE_FULL_PACKET)
failed = 1;
failed = true;
psmouse_set_state(psmouse, PSMOUSE_RESYNCING);
}
}
@ -1051,7 +1075,7 @@ static void psmouse_resync(struct work_struct *work)
*/
for (i = 0; i < 5; i++) {
if (!ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_ENABLE)) {
enabled = 1;
enabled = true;
break;
}
msleep(200);
@ -1060,7 +1084,7 @@ static void psmouse_resync(struct work_struct *work)
if (!enabled) {
printk(KERN_WARNING "psmouse.c: failed to re-enable mouse on %s\n",
psmouse->ps2dev.serio->phys);
failed = 1;
failed = true;
}
if (failed) {
@ -1187,7 +1211,8 @@ static int psmouse_switch_protocol(struct psmouse *psmouse, const struct psmouse
psmouse->type = proto->type;
}
else
psmouse->type = psmouse_extensions(psmouse, psmouse_max_proto, 1);
psmouse->type = psmouse_extensions(psmouse,
psmouse_max_proto, true);
/*
* If mouse's packet size is 3 there is no point in polling the
@ -1342,8 +1367,10 @@ static int psmouse_reconnect(struct serio *serio)
if (psmouse->reconnect(psmouse))
goto out;
} else if (psmouse_probe(psmouse) < 0 ||
psmouse->type != psmouse_extensions(psmouse, psmouse_max_proto, 0))
psmouse->type != psmouse_extensions(psmouse,
psmouse_max_proto, false)) {
goto out;
}
/* ok, the device type (and capabilities) match the old one,
* we can continue using it, complete intialization
@ -1528,7 +1555,9 @@ static ssize_t psmouse_attr_set_protocol(struct psmouse *psmouse, void *data, co
while (serio->child) {
if (++retry > 3) {
printk(KERN_WARNING "psmouse: failed to destroy child port, protocol change aborted.\n");
printk(KERN_WARNING
"psmouse: failed to destroy child port, "
"protocol change aborted.\n");
input_free_device(new_dev);
return -EIO;
}

View file

@ -47,10 +47,10 @@ struct psmouse {
unsigned char pktcnt;
unsigned char pktsize;
unsigned char type;
unsigned char acks_disable_command;
bool acks_disable_command;
unsigned int model;
unsigned long last;
unsigned long out_of_sync;
unsigned long out_of_sync_cnt;
unsigned long num_resyncs;
enum psmouse_state state;
char devname[64];
@ -60,7 +60,7 @@ struct psmouse {
unsigned int resolution;
unsigned int resetafter;
unsigned int resync_time;
unsigned int smartscroll; /* Logitech only */
bool smartscroll; /* Logitech only */
psmouse_ret_t (*protocol_handler)(struct psmouse *psmouse);
void (*set_rate)(struct psmouse *psmouse, unsigned int rate);
@ -91,6 +91,7 @@ enum psmouse_type {
PSMOUSE_CORTRON,
PSMOUSE_HGPK,
PSMOUSE_ELANTECH,
PSMOUSE_FSP,
PSMOUSE_AUTO /* This one should always be last */
};
@ -107,7 +108,7 @@ struct psmouse_attribute {
ssize_t (*show)(struct psmouse *psmouse, void *data, char *buf);
ssize_t (*set)(struct psmouse *psmouse, void *data,
const char *buf, size_t count);
int protect;
bool protect;
};
#define to_psmouse_attr(a) container_of((a), struct psmouse_attribute, dattr)
@ -116,9 +117,7 @@ ssize_t psmouse_attr_show_helper(struct device *dev, struct device_attribute *at
ssize_t psmouse_attr_set_helper(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count);
#define __PSMOUSE_DEFINE_ATTR(_name, _mode, _data, _show, _set, _protect) \
static ssize_t _show(struct psmouse *, void *data, char *); \
static ssize_t _set(struct psmouse *, void *data, const char *, size_t); \
#define __PSMOUSE_DEFINE_ATTR_VAR(_name, _mode, _data, _show, _set, _protect) \
static struct psmouse_attribute psmouse_attr_##_name = { \
.dattr = { \
.attr = { \
@ -134,7 +133,20 @@ static struct psmouse_attribute psmouse_attr_##_name = { \
.protect = _protect, \
}
#define PSMOUSE_DEFINE_ATTR(_name, _mode, _data, _show, _set) \
__PSMOUSE_DEFINE_ATTR(_name, _mode, _data, _show, _set, 1)
#define __PSMOUSE_DEFINE_ATTR(_name, _mode, _data, _show, _set, _protect) \
static ssize_t _show(struct psmouse *, void *, char *); \
static ssize_t _set(struct psmouse *, void *, const char *, size_t); \
__PSMOUSE_DEFINE_ATTR_VAR(_name, _mode, _data, _show, _set, _protect)
#define PSMOUSE_DEFINE_ATTR(_name, _mode, _data, _show, _set) \
__PSMOUSE_DEFINE_ATTR(_name, _mode, _data, _show, _set, true)
#define PSMOUSE_DEFINE_RO_ATTR(_name, _mode, _data, _show) \
static ssize_t _show(struct psmouse *, void *, char *); \
__PSMOUSE_DEFINE_ATTR_VAR(_name, _mode, _data, _show, NULL, true)
#define PSMOUSE_DEFINE_WO_ATTR(_name, _mode, _data, _set) \
static ssize_t _set(struct psmouse *, void *, const char *, size_t); \
__PSMOUSE_DEFINE_ATTR_VAR(_name, _mode, _data, NULL, _set, true)
#endif /* _PSMOUSE_H */

View 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) || 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;
}

View 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 */

View file

@ -60,7 +60,7 @@ static int synaptics_mode_cmd(struct psmouse *psmouse, unsigned char mode)
return 0;
}
int synaptics_detect(struct psmouse *psmouse, int set_properties)
int synaptics_detect(struct psmouse *psmouse, bool set_properties)
{
struct ps2dev *ps2dev = &psmouse->ps2dev;
unsigned char param[4];
@ -556,38 +556,38 @@ static void set_input_params(struct input_dev *dev, struct synaptics_data *priv)
{
int i;
set_bit(EV_ABS, dev->evbit);
__set_bit(EV_ABS, dev->evbit);
input_set_abs_params(dev, ABS_X, XMIN_NOMINAL, XMAX_NOMINAL, 0, 0);
input_set_abs_params(dev, ABS_Y, YMIN_NOMINAL, YMAX_NOMINAL, 0, 0);
input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0);
set_bit(ABS_TOOL_WIDTH, dev->absbit);
__set_bit(ABS_TOOL_WIDTH, dev->absbit);
set_bit(EV_KEY, dev->evbit);
set_bit(BTN_TOUCH, dev->keybit);
set_bit(BTN_TOOL_FINGER, dev->keybit);
set_bit(BTN_LEFT, dev->keybit);
set_bit(BTN_RIGHT, dev->keybit);
__set_bit(EV_KEY, dev->evbit);
__set_bit(BTN_TOUCH, dev->keybit);
__set_bit(BTN_TOOL_FINGER, dev->keybit);
__set_bit(BTN_LEFT, dev->keybit);
__set_bit(BTN_RIGHT, dev->keybit);
if (SYN_CAP_MULTIFINGER(priv->capabilities)) {
set_bit(BTN_TOOL_DOUBLETAP, dev->keybit);
set_bit(BTN_TOOL_TRIPLETAP, dev->keybit);
__set_bit(BTN_TOOL_DOUBLETAP, dev->keybit);
__set_bit(BTN_TOOL_TRIPLETAP, dev->keybit);
}
if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities))
set_bit(BTN_MIDDLE, dev->keybit);
__set_bit(BTN_MIDDLE, dev->keybit);
if (SYN_CAP_FOUR_BUTTON(priv->capabilities) ||
SYN_CAP_MIDDLE_BUTTON(priv->capabilities)) {
set_bit(BTN_FORWARD, dev->keybit);
set_bit(BTN_BACK, dev->keybit);
__set_bit(BTN_FORWARD, dev->keybit);
__set_bit(BTN_BACK, dev->keybit);
}
for (i = 0; i < SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap); i++)
set_bit(BTN_0 + i, dev->keybit);
__set_bit(BTN_0 + i, dev->keybit);
clear_bit(EV_REL, dev->evbit);
clear_bit(REL_X, dev->relbit);
clear_bit(REL_Y, dev->relbit);
__clear_bit(EV_REL, dev->evbit);
__clear_bit(REL_X, dev->relbit);
__clear_bit(REL_Y, dev->relbit);
dev->absres[ABS_X] = priv->x_res;
dev->absres[ABS_Y] = priv->y_res;

View file

@ -105,7 +105,7 @@ struct synaptics_data {
int scroll;
};
int synaptics_detect(struct psmouse *psmouse, int set_properties);
int synaptics_detect(struct psmouse *psmouse, bool set_properties);
int synaptics_init(struct psmouse *psmouse);
void synaptics_reset(struct psmouse *psmouse);

View file

@ -67,7 +67,7 @@ static psmouse_ret_t touchkit_ps2_process_byte(struct psmouse *psmouse)
return PSMOUSE_FULL_PACKET;
}
int touchkit_ps2_detect(struct psmouse *psmouse, int set_properties)
int touchkit_ps2_detect(struct psmouse *psmouse, bool set_properties)
{
struct input_dev *dev = psmouse->dev;
unsigned char param[3];
@ -86,7 +86,7 @@ int touchkit_ps2_detect(struct psmouse *psmouse, int set_properties)
if (set_properties) {
dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
set_bit(BTN_TOUCH, dev->keybit);
__set_bit(BTN_TOUCH, dev->keybit);
input_set_abs_params(dev, ABS_X, 0, TOUCHKIT_MAX_XC, 0, 0);
input_set_abs_params(dev, ABS_Y, 0, TOUCHKIT_MAX_YC, 0, 0);

View file

@ -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;
}

View file

@ -282,7 +282,7 @@ static int trackpoint_reconnect(struct psmouse *psmouse)
return 0;
}
int trackpoint_detect(struct psmouse *psmouse, int set_properties)
int trackpoint_detect(struct psmouse *psmouse, bool set_properties)
{
struct trackpoint_data *priv;
struct ps2dev *ps2dev = &psmouse->ps2dev;

View file

@ -143,9 +143,9 @@ struct trackpoint_data
};
#ifdef CONFIG_MOUSE_PS2_TRACKPOINT
int trackpoint_detect(struct psmouse *psmouse, int set_properties);
int trackpoint_detect(struct psmouse *psmouse, bool set_properties);
#else
inline int trackpoint_detect(struct psmouse *psmouse, int set_properties)
inline int trackpoint_detect(struct psmouse *psmouse, bool set_properties)
{
return -ENOSYS;
}

View file

@ -384,11 +384,11 @@ vsxxxaa_handle_POR_packet (struct vsxxxaa *mouse)
printk (KERN_NOTICE "%s on %s: Forceing standard packet format, "
"incremental streaming mode and 72 samples/sec\n",
mouse->name, mouse->phys);
mouse->serio->write (mouse->serio, 'S'); /* Standard format */
serio_write (mouse->serio, 'S'); /* Standard format */
mdelay (50);
mouse->serio->write (mouse->serio, 'R'); /* Incremental */
serio_write (mouse->serio, 'R'); /* Incremental */
mdelay (50);
mouse->serio->write (mouse->serio, 'L'); /* 72 samples/sec */
serio_write (mouse->serio, 'L'); /* 72 samples/sec */
}
static void
@ -532,7 +532,7 @@ vsxxxaa_connect (struct serio *serio, struct serio_driver *drv)
* Request selftest. Standard packet format and differential
* mode will be requested after the device ID'ed successfully.
*/
serio->write (serio, 'T'); /* Test */
serio_write (serio, 'T'); /* Test */
err = input_register_device (input_dev);
if (err)

View file

@ -231,7 +231,7 @@ static int __init psif_probe(struct platform_device *pdev)
goto out_free_io;
}
psif->regs = ioremap(regs->start, regs->end - regs->start + 1);
psif->regs = ioremap(regs->start, resource_size(regs));
if (!psif->regs) {
ret = -ENOMEM;
dev_dbg(&pdev->dev, "could not map I/O memory\n");

View file

@ -457,6 +457,34 @@ static struct dmi_system_id __initdata i8042_dmi_nopnp_table[] = {
},
{ }
};
static struct dmi_system_id __initdata i8042_dmi_laptop_table[] = {
{
.ident = "Portable",
.matches = {
DMI_MATCH(DMI_CHASSIS_TYPE, "8"), /* Portable */
},
},
{
.ident = "Laptop",
.matches = {
DMI_MATCH(DMI_CHASSIS_TYPE, "9"), /* Laptop */
},
},
{
.ident = "Notebook",
.matches = {
DMI_MATCH(DMI_CHASSIS_TYPE, "10"), /* Notebook */
},
},
{
.ident = "Sub-Notebook",
.matches = {
DMI_MATCH(DMI_CHASSIS_TYPE, "14"), /* Sub-Notebook */
},
},
{ }
};
#endif
/*
@ -530,9 +558,9 @@ static struct dmi_system_id __initdata i8042_dmi_dritek_table[] = {
#ifdef CONFIG_PNP
#include <linux/pnp.h>
static int i8042_pnp_kbd_registered;
static bool i8042_pnp_kbd_registered;
static unsigned int i8042_pnp_kbd_devices;
static int i8042_pnp_aux_registered;
static bool i8042_pnp_aux_registered;
static unsigned int i8042_pnp_aux_devices;
static int i8042_pnp_command_reg;
@ -620,12 +648,12 @@ static struct pnp_driver i8042_pnp_aux_driver = {
static void i8042_pnp_exit(void)
{
if (i8042_pnp_kbd_registered) {
i8042_pnp_kbd_registered = 0;
i8042_pnp_kbd_registered = false;
pnp_unregister_driver(&i8042_pnp_kbd_driver);
}
if (i8042_pnp_aux_registered) {
i8042_pnp_aux_registered = 0;
i8042_pnp_aux_registered = false;
pnp_unregister_driver(&i8042_pnp_aux_driver);
}
}
@ -633,12 +661,12 @@ static void i8042_pnp_exit(void)
static int __init i8042_pnp_init(void)
{
char kbd_irq_str[4] = { 0 }, aux_irq_str[4] = { 0 };
int pnp_data_busted = 0;
int pnp_data_busted = false;
int err;
#ifdef CONFIG_X86
if (dmi_check_system(i8042_dmi_nopnp_table))
i8042_nopnp = 1;
i8042_nopnp = true;
#endif
if (i8042_nopnp) {
@ -648,11 +676,11 @@ static int __init i8042_pnp_init(void)
err = pnp_register_driver(&i8042_pnp_kbd_driver);
if (!err)
i8042_pnp_kbd_registered = 1;
i8042_pnp_kbd_registered = true;
err = pnp_register_driver(&i8042_pnp_aux_driver);
if (!err)
i8042_pnp_aux_registered = 1;
i8042_pnp_aux_registered = true;
if (!i8042_pnp_kbd_devices && !i8042_pnp_aux_devices) {
i8042_pnp_exit();
@ -680,9 +708,9 @@ static int __init i8042_pnp_init(void)
#if defined(__ia64__)
if (!i8042_pnp_kbd_devices)
i8042_nokbd = 1;
i8042_nokbd = true;
if (!i8042_pnp_aux_devices)
i8042_noaux = 1;
i8042_noaux = true;
#endif
if (((i8042_pnp_data_reg & ~0xf) == (i8042_data_reg & ~0xf) &&
@ -693,7 +721,7 @@ static int __init i8042_pnp_init(void)
"using default %#x\n",
i8042_pnp_data_reg, i8042_data_reg);
i8042_pnp_data_reg = i8042_data_reg;
pnp_data_busted = 1;
pnp_data_busted = true;
}
if (((i8042_pnp_command_reg & ~0xf) == (i8042_command_reg & ~0xf) &&
@ -704,7 +732,7 @@ static int __init i8042_pnp_init(void)
"using default %#x\n",
i8042_pnp_command_reg, i8042_command_reg);
i8042_pnp_command_reg = i8042_command_reg;
pnp_data_busted = 1;
pnp_data_busted = true;
}
if (!i8042_nokbd && !i8042_pnp_kbd_irq) {
@ -712,7 +740,7 @@ static int __init i8042_pnp_init(void)
"PNP: PS/2 controller doesn't have KBD irq; "
"using default %d\n", i8042_kbd_irq);
i8042_pnp_kbd_irq = i8042_kbd_irq;
pnp_data_busted = 1;
pnp_data_busted = true;
}
if (!i8042_noaux && !i8042_pnp_aux_irq) {
@ -721,7 +749,7 @@ static int __init i8042_pnp_init(void)
"PNP: PS/2 appears to have AUX port disabled, "
"if this is incorrect please boot with "
"i8042.nopnp\n");
i8042_noaux = 1;
i8042_noaux = true;
} else {
printk(KERN_WARNING
"PNP: PS/2 controller doesn't have AUX irq; "
@ -735,6 +763,11 @@ static int __init i8042_pnp_init(void)
i8042_kbd_irq = i8042_pnp_kbd_irq;
i8042_aux_irq = i8042_pnp_aux_irq;
#ifdef CONFIG_X86
i8042_bypass_aux_irq_test = !pnp_data_busted &&
dmi_check_system(i8042_dmi_laptop_table);
#endif
return 0;
}
@ -763,21 +796,21 @@ static int __init i8042_platform_init(void)
return retval;
#if defined(__ia64__)
i8042_reset = 1;
i8042_reset = true;
#endif
#ifdef CONFIG_X86
if (dmi_check_system(i8042_dmi_reset_table))
i8042_reset = 1;
i8042_reset = true;
if (dmi_check_system(i8042_dmi_noloop_table))
i8042_noloop = 1;
i8042_noloop = true;
if (dmi_check_system(i8042_dmi_nomux_table))
i8042_nomux = 1;
i8042_nomux = true;
if (dmi_check_system(i8042_dmi_dritek_table))
i8042_dritek = 1;
i8042_dritek = true;
#endif /* CONFIG_X86 */
return retval;

View file

@ -28,35 +28,35 @@ MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
MODULE_DESCRIPTION("i8042 keyboard and mouse controller driver");
MODULE_LICENSE("GPL");
static unsigned int i8042_nokbd;
static bool i8042_nokbd;
module_param_named(nokbd, i8042_nokbd, bool, 0);
MODULE_PARM_DESC(nokbd, "Do not probe or use KBD port.");
static unsigned int i8042_noaux;
static bool i8042_noaux;
module_param_named(noaux, i8042_noaux, bool, 0);
MODULE_PARM_DESC(noaux, "Do not probe or use AUX (mouse) port.");
static unsigned int i8042_nomux;
static bool i8042_nomux;
module_param_named(nomux, i8042_nomux, bool, 0);
MODULE_PARM_DESC(nomux, "Do not check whether an active multiplexing conrtoller is present.");
static unsigned int i8042_unlock;
static bool i8042_unlock;
module_param_named(unlock, i8042_unlock, bool, 0);
MODULE_PARM_DESC(unlock, "Ignore keyboard lock.");
static unsigned int i8042_reset;
static bool i8042_reset;
module_param_named(reset, i8042_reset, bool, 0);
MODULE_PARM_DESC(reset, "Reset controller during init and cleanup.");
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(&param, I8042_CMD_AUX_LOOP) || param != 0xf0)
param = val = 0xf0;
if (i8042_command(&param, I8042_CMD_AUX_LOOP) || param != val)
return -1;
param = mode ? 0x56 : 0xf6;
if (i8042_command(&param, I8042_CMD_AUX_LOOP) || param != (mode ? 0x56 : 0xf6))
param = val = multiplex ? 0x56 : 0xf6;
if (i8042_command(&param, I8042_CMD_AUX_LOOP) || param != val)
return -1;
param = mode ? 0xa4 : 0xa5;
if (i8042_command(&param, I8042_CMD_AUX_LOOP) || param == (mode ? 0xa4 : 0xa5))
param = val = multiplex ? 0xa4 : 0xa5;
if (i8042_command(&param, 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(&param, 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;

View file

@ -161,7 +161,7 @@ static int ps2_adjust_timeout(struct ps2dev *ps2dev, int command, int timeout)
* ps2_command() can only be called from a process context
*/
int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command)
int __ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command)
{
int timeout;
int send = (command >> 12) & 0xf;
@ -179,8 +179,6 @@ int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command)
return -1;
}
mutex_lock(&ps2dev->cmd_mutex);
serio_pause_rx(ps2dev->serio);
ps2dev->flags = command == PS2_CMD_GETID ? PS2_FLAG_WAITID : 0;
ps2dev->cmdcnt = receive;
@ -231,7 +229,18 @@ int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command)
ps2dev->flags = 0;
serio_continue_rx(ps2dev->serio);
return rc;
}
EXPORT_SYMBOL(__ps2_command);
int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command)
{
int rc;
mutex_lock(&ps2dev->cmd_mutex);
rc = __ps2_command(ps2dev, param, command);
mutex_unlock(&ps2dev->cmd_mutex);
return rc;
}
EXPORT_SYMBOL(ps2_command);

View file

@ -931,15 +931,11 @@ static int serio_uevent(struct device *dev, struct kobj_uevent_env *env)
#endif /* CONFIG_HOTPLUG */
#ifdef CONFIG_PM
static int serio_suspend(struct device *dev, pm_message_t state)
static int serio_suspend(struct device *dev)
{
struct serio *serio = to_serio_port(dev);
if (!serio->suspended && state.event == PM_EVENT_SUSPEND)
serio_cleanup(serio);
serio->suspended = state.event == PM_EVENT_SUSPEND ||
state.event == PM_EVENT_FREEZE;
serio_cleanup(serio);
return 0;
}
@ -952,13 +948,17 @@ static int serio_resume(struct device *dev)
* Driver reconnect can take a while, so better let kseriod
* deal with it.
*/
if (serio->suspended) {
serio->suspended = false;
serio_queue_event(serio, NULL, SERIO_RECONNECT_PORT);
}
serio_queue_event(serio, NULL, SERIO_RECONNECT_PORT);
return 0;
}
static const struct dev_pm_ops serio_pm_ops = {
.suspend = serio_suspend,
.resume = serio_resume,
.poweroff = serio_suspend,
.restore = serio_resume,
};
#endif /* CONFIG_PM */
/* called from serio_driver->connect/disconnect methods under serio_mutex */
@ -1015,8 +1015,7 @@ static struct bus_type serio_bus = {
.remove = serio_driver_remove,
.shutdown = serio_shutdown,
#ifdef CONFIG_PM
.suspend = serio_suspend,
.resume = serio_resume,
.pm = &serio_pm_ops,
#endif
};

View file

@ -366,11 +366,11 @@ config TOUCHSCREEN_WM97XX_ATMEL
be called atmel-wm97xx.
config TOUCHSCREEN_WM97XX_MAINSTONE
tristate "WM97xx Mainstone accelerated touch"
tristate "WM97xx Mainstone/Palm accelerated touch"
depends on TOUCHSCREEN_WM97XX && ARCH_PXA
help
Say Y here for support for streaming mode with WM97xx touchscreens
on Mainstone systems.
on Mainstone, Palm Tungsten T5, TX and LifeDrive systems.
If unsure, say N.
@ -406,6 +406,7 @@ config TOUCHSCREEN_USB_COMPOSITE
- IRTOUCHSYSTEMS/UNITOP
- IdealTEK URTC1000
- GoTop Super_Q2/GogoPen/PenPower tablets
- JASTEC USB Touch Controller/DigiTech DTR-02U
Have a look at <http://linux.chapter7.ch/touchkit/> for
a usage description and the required user-space stuff.
@ -468,6 +469,16 @@ config TOUCHSCREEN_USB_GOTOP
bool "GoTop Super_Q2/GogoPen/PenPower tablet device support" if EMBEDDED
depends on TOUCHSCREEN_USB_COMPOSITE
config TOUCHSCREEN_USB_JASTEC
default y
bool "JASTEC/DigiTech DTR-02U USB touch controller device support" if EMBEDDED
depends on TOUCHSCREEN_USB_COMPOSITE
config TOUCHSCREEN_USB_E2I
default y
bool "e2i Touchscreen controller (e.g. from Mimo 740)"
depends on TOUCHSCREEN_USB_COMPOSITE
config TOUCHSCREEN_TOUCHIT213
tristate "Sahara TouchIT-213 touchscreen"
select SERIO
@ -492,6 +503,7 @@ config TOUCHSCREEN_TSC2007
config TOUCHSCREEN_W90X900
tristate "W90P910 touchscreen driver"
depends on HAVE_CLK
help
Say Y here if you have a W90P910 based touchscreen.

View file

@ -204,14 +204,14 @@ static int __devinit atmel_tsadcc_probe(struct platform_device *pdev)
goto err_free_dev;
}
if (!request_mem_region(res->start, res->end - res->start + 1,
if (!request_mem_region(res->start, resource_size(res),
"atmel tsadcc regs")) {
dev_err(&pdev->dev, "resources is unavailable.\n");
err = -EBUSY;
goto err_free_dev;
}
tsc_base = ioremap(res->start, res->end - res->start + 1);
tsc_base = ioremap(res->start, resource_size(res));
if (!tsc_base) {
dev_err(&pdev->dev, "failed to map registers.\n");
err = -ENOMEM;
@ -286,7 +286,7 @@ 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);

View file

@ -32,6 +32,7 @@
#include <linux/i2c.h>
#include <linux/timer.h>
#include <linux/gpio.h>
#include <linux/input/eeti_ts.h>
static int flip_x;
module_param(flip_x, bool, 0644);
@ -46,7 +47,7 @@ struct eeti_ts_priv {
struct input_dev *input;
struct work_struct work;
struct mutex mutex;
int irq;
int irq, irq_active_high;
};
#define EETI_TS_BITDEPTH (11)
@ -58,6 +59,11 @@ struct eeti_ts_priv {
#define REPORT_BIT_HAS_PRESSURE (1 << 6)
#define REPORT_RES_BITS(v) (((v) >> 1) + EETI_TS_BITDEPTH)
static inline int eeti_ts_irq_active(struct eeti_ts_priv *priv)
{
return gpio_get_value(irq_to_gpio(priv->irq)) == priv->irq_active_high;
}
static void eeti_ts_read(struct work_struct *work)
{
char buf[6];
@ -67,7 +73,7 @@ static void eeti_ts_read(struct work_struct *work)
mutex_lock(&priv->mutex);
while (!gpio_get_value(irq_to_gpio(priv->irq)) && --to)
while (eeti_ts_irq_active(priv) && --to)
i2c_master_recv(priv->client, buf, sizeof(buf));
if (!to) {
@ -140,8 +146,10 @@ static void eeti_ts_close(struct input_dev *dev)
static int __devinit eeti_ts_probe(struct i2c_client *client,
const struct i2c_device_id *idp)
{
struct eeti_ts_platform_data *pdata;
struct eeti_ts_priv *priv;
struct input_dev *input;
unsigned int irq_flags;
int err = -ENOMEM;
/* In contrast to what's described in the datasheet, there seems
@ -180,6 +188,14 @@ static int __devinit eeti_ts_probe(struct i2c_client *client,
priv->input = input;
priv->irq = client->irq;
pdata = client->dev.platform_data;
if (pdata)
priv->irq_active_high = pdata->irq_active_high;
irq_flags = priv->irq_active_high ?
IRQF_TRIGGER_RISING : IRQF_TRIGGER_FALLING;
INIT_WORK(&priv->work, eeti_ts_read);
i2c_set_clientdata(client, priv);
input_set_drvdata(input, priv);
@ -188,7 +204,7 @@ static int __devinit eeti_ts_probe(struct i2c_client *client,
if (err)
goto err1;
err = request_irq(priv->irq, eeti_ts_isr, IRQF_TRIGGER_FALLING,
err = request_irq(priv->irq, eeti_ts_isr, irq_flags,
client->name, priv);
if (err) {
dev_err(&client->dev, "Unable to request touchscreen IRQ.\n");

View file

@ -148,9 +148,10 @@ unsigned int h3600_flite_power(struct input_dev *dev, enum flite_pwr pwr)
struct h3600_dev *ts = input_get_drvdata(dev);
/* Must be in this order */
ts->serio->write(ts->serio, 1);
ts->serio->write(ts->serio, pwr);
ts->serio->write(ts->serio, brightness);
serio_write(ts->serio, 1);
serio_write(ts->serio, pwr);
serio_write(ts->serio, brightness);
return 0;
}
@ -262,7 +263,7 @@ static int h3600ts_event(struct input_dev *dev, unsigned int type,
switch (type) {
case EV_LED: {
// ts->serio->write(ts->serio, SOME_CMD);
// serio_write(ts->serio, SOME_CMD);
return 0;
}
}

View file

@ -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;
}
}

View file

@ -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)

View file

@ -128,9 +128,10 @@ static inline unsigned int ucb1400_ts_read_yres(struct ucb1400_ts *ucb)
return ucb1400_adc_read(ucb->ac97, 0, adcsync);
}
static inline int ucb1400_ts_pen_down(struct snd_ac97 *ac97)
static inline int ucb1400_ts_pen_up(struct snd_ac97 *ac97)
{
unsigned short val = ucb1400_reg_read(ac97, UCB_TS_CR);
return val & (UCB_TS_CR_TSPX_LOW | UCB_TS_CR_TSMX_LOW);
}
@ -209,7 +210,7 @@ static int ucb1400_ts_thread(void *_ucb)
msleep(10);
if (ucb1400_ts_pen_down(ucb->ac97)) {
if (ucb1400_ts_pen_up(ucb->ac97)) {
ucb1400_ts_irq_enable(ucb->ac97);
/*

View file

@ -13,6 +13,7 @@
* - IdealTEK URTC1000
* - General Touch
* - GoTop Super_Q2/GogoPen/PenPower tablets
* - JASTEC USB touch controller/DigiTech DTR-02U
*
* Copyright (C) 2004-2007 by Daniel Ritz <daniel.ritz@gmx.ch>
* Copyright (C) by Todd E. Johnson (mtouchusb.c)
@ -118,6 +119,8 @@ enum {
DEVTYPE_IDEALTEK,
DEVTYPE_GENERAL_TOUCH,
DEVTYPE_GOTOP,
DEVTYPE_JASTEC,
DEVTYPE_E2I,
};
#define USB_DEVICE_HID_CLASS(vend, prod) \
@ -191,10 +194,50 @@ static struct usb_device_id usbtouch_devices[] = {
{USB_DEVICE(0x08f2, 0x00f4), .driver_info = DEVTYPE_GOTOP},
#endif
#ifdef CONFIG_TOUCHSCREEN_USB_JASTEC
{USB_DEVICE(0x0f92, 0x0001), .driver_info = DEVTYPE_JASTEC},
#endif
#ifdef CONFIG_TOUCHSCREEN_USB_E2I
{USB_DEVICE(0x1ac7, 0x0001), .driver_info = DEVTYPE_E2I},
#endif
{}
};
/*****************************************************************************
* e2i Part
*/
#ifdef CONFIG_TOUCHSCREEN_USB_E2I
static int e2i_init(struct usbtouch_usb *usbtouch)
{
int ret;
ret = usb_control_msg(usbtouch->udev, usb_rcvctrlpipe(usbtouch->udev, 0),
0x01, 0x02, 0x0000, 0x0081,
NULL, 0, USB_CTRL_SET_TIMEOUT);
dbg("%s - usb_control_msg - E2I_RESET - bytes|err: %d",
__func__, ret);
return ret;
}
static int e2i_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
{
int tmp = (pkt[0] << 8) | pkt[1];
dev->x = (pkt[2] << 8) | pkt[3];
dev->y = (pkt[4] << 8) | pkt[5];
tmp = tmp - 0xA000;
dev->touch = (tmp > 0);
dev->press = (tmp > 0 ? tmp : 0);
return 1;
}
#endif
/*****************************************************************************
* eGalax part
*/
@ -559,6 +602,21 @@ static int gotop_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
dev->x = ((pkt[1] & 0x38) << 4) | pkt[2];
dev->y = ((pkt[1] & 0x07) << 7) | pkt[3];
dev->touch = pkt[0] & 0x01;
return 1;
}
#endif
/*****************************************************************************
* JASTEC Part
*/
#ifdef CONFIG_TOUCHSCREEN_USB_JASTEC
static int jastec_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
{
dev->x = ((pkt[0] & 0x3f) << 6) | (pkt[2] & 0x3f);
dev->y = ((pkt[1] & 0x3f) << 6) | (pkt[3] & 0x3f);
dev->touch = (pkt[0] & 0x40) >> 6;
return 1;
}
#endif
@ -702,6 +760,29 @@ static struct usbtouch_device_info usbtouch_dev_info[] = {
.read_data = gotop_read_data,
},
#endif
#ifdef CONFIG_TOUCHSCREEN_USB_JASTEC
[DEVTYPE_JASTEC] = {
.min_xc = 0x0,
.max_xc = 0x0fff,
.min_yc = 0x0,
.max_yc = 0x0fff,
.rept_size = 4,
.read_data = jastec_read_data,
},
#endif
#ifdef CONFIG_TOUCHSCREEN_USB_E2I
[DEVTYPE_E2I] = {
.min_xc = 0x0,
.max_xc = 0x7fff,
.min_yc = 0x0,
.max_yc = 0x7fff,
.rept_size = 6,
.init = e2i_init,
.read_data = e2i_read_data,
},
#endif
};

View file

@ -13,6 +13,7 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/clk.h>
#include <linux/input.h>
#include <linux/interrupt.h>
@ -47,8 +48,8 @@ enum ts_state {
struct w90p910_ts {
struct input_dev *input;
struct timer_list timer;
struct clk *clk;
int irq_num;
void __iomem *clocken;
void __iomem *ts_reg;
spinlock_t lock;
enum ts_state state;
@ -166,8 +167,7 @@ static int w90p910_open(struct input_dev *dev)
unsigned long val;
/* enable the ADC clock */
val = __raw_readl(w90p910_ts->clocken);
__raw_writel(val | ADC_CLK_EN, w90p910_ts->clocken);
clk_enable(w90p910_ts->clk);
__raw_writel(ADC_RST1, w90p910_ts->ts_reg);
msleep(1);
@ -211,8 +211,7 @@ static void w90p910_close(struct input_dev *dev)
del_timer_sync(&w90p910_ts->timer);
/* stop the ADC clock */
val = __raw_readl(w90p910_ts->clocken);
__raw_writel(val & ~ADC_CLK_EN, w90p910_ts->clocken);
clk_disable(w90p910_ts->clk);
}
static int __devinit w90x900ts_probe(struct platform_device *pdev)
@ -241,26 +240,24 @@ static int __devinit w90x900ts_probe(struct platform_device *pdev)
goto fail1;
}
if (!request_mem_region(res->start, res->end - res->start + 1,
if (!request_mem_region(res->start, resource_size(res),
pdev->name)) {
err = -EBUSY;
goto fail1;
}
w90p910_ts->ts_reg = ioremap(res->start, res->end - res->start + 1);
w90p910_ts->ts_reg = ioremap(res->start, resource_size(res));
if (!w90p910_ts->ts_reg) {
err = -ENOMEM;
goto fail2;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
if (!res) {
err = -ENXIO;
w90p910_ts->clk = clk_get(&pdev->dev, NULL);
if (IS_ERR(w90p910_ts->clk)) {
err = PTR_ERR(w90p910_ts->clk);
goto fail3;
}
w90p910_ts->clocken = (void __iomem *)res->start;
input_dev->name = "W90P910 TouchScreen";
input_dev->phys = "w90p910ts/event0";
input_dev->id.bustype = BUS_HOST;
@ -283,20 +280,21 @@ static int __devinit w90x900ts_probe(struct platform_device *pdev)
if (request_irq(w90p910_ts->irq_num, w90p910_ts_interrupt,
IRQF_DISABLED, "w90p910ts", w90p910_ts)) {
err = -EBUSY;
goto fail3;
goto fail4;
}
err = input_register_device(w90p910_ts->input);
if (err)
goto fail4;
goto fail5;
platform_set_drvdata(pdev, w90p910_ts);
return 0;
fail4: free_irq(w90p910_ts->irq_num, w90p910_ts);
fail5: free_irq(w90p910_ts->irq_num, w90p910_ts);
fail4: clk_put(w90p910_ts->clk);
fail3: iounmap(w90p910_ts->ts_reg);
fail2: release_mem_region(res->start, res->end - res->start + 1);
fail2: release_mem_region(res->start, resource_size(res));
fail1: input_free_device(input_dev);
kfree(w90p910_ts);
return err;
@ -311,8 +309,10 @@ static int __devexit w90x900ts_remove(struct platform_device *pdev)
del_timer_sync(&w90p910_ts->timer);
iounmap(w90p910_ts->ts_reg);
clk_put(w90p910_ts->clk);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
release_mem_region(res->start, res->end - res->start + 1);
release_mem_region(res->start, resource_size(res));
input_unregister_device(w90p910_ts->input);
kfree(w90p910_ts);

View file

@ -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);

View file

@ -204,7 +204,7 @@ void wm97xx_set_gpio(struct wm97xx *wm, u32 gpio,
else
reg &= ~gpio;
if (wm->id == WM9712_ID2)
if (wm->id == WM9712_ID2 && wm->variant != WM97xx_WM1613)
wm97xx_reg_write(wm, AC97_GPIO_STATUS, reg << 1);
else
wm97xx_reg_write(wm, AC97_GPIO_STATUS, reg);
@ -307,7 +307,7 @@ static void wm97xx_pen_irq_worker(struct work_struct *work)
WM97XX_GPIO_13);
}
if (wm->id == WM9712_ID2)
if (wm->id == WM9712_ID2 && wm->variant != WM97xx_WM1613)
wm97xx_reg_write(wm, AC97_GPIO_STATUS, (status &
~WM97XX_GPIO_13) << 1);
else
@ -582,6 +582,8 @@ static int wm97xx_probe(struct device *dev)
wm->id = wm97xx_reg_read(wm, AC97_VENDOR_ID2);
wm->variant = WM97xx_GENERIC;
dev_info(wm->dev, "detected a wm97%02x codec\n", wm->id & 0xff);
switch (wm->id & 0xff) {

View file

@ -575,7 +575,7 @@ static void pci_pm_complete(struct device *dev)
static int pci_pm_suspend(struct device *dev)
{
struct pci_dev *pci_dev = to_pci_dev(dev);
struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
if (pci_has_legacy_pm_support(pci_dev))
return pci_legacy_suspend(dev, PMSG_SUSPEND);
@ -613,7 +613,7 @@ static int pci_pm_suspend(struct device *dev)
static int pci_pm_suspend_noirq(struct device *dev)
{
struct pci_dev *pci_dev = to_pci_dev(dev);
struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
if (pci_has_legacy_pm_support(pci_dev))
return pci_legacy_suspend_late(dev, PMSG_SUSPEND);
@ -672,7 +672,7 @@ static int pci_pm_resume_noirq(struct device *dev)
static int pci_pm_resume(struct device *dev)
{
struct pci_dev *pci_dev = to_pci_dev(dev);
struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
int error = 0;
/*
@ -711,7 +711,7 @@ static int pci_pm_resume(struct device *dev)
static int pci_pm_freeze(struct device *dev)
{
struct pci_dev *pci_dev = to_pci_dev(dev);
struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
if (pci_has_legacy_pm_support(pci_dev))
return pci_legacy_suspend(dev, PMSG_FREEZE);
@ -780,7 +780,7 @@ static int pci_pm_thaw_noirq(struct device *dev)
static int pci_pm_thaw(struct device *dev)
{
struct pci_dev *pci_dev = to_pci_dev(dev);
struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
int error = 0;
if (pci_has_legacy_pm_support(pci_dev))
@ -799,7 +799,7 @@ static int pci_pm_thaw(struct device *dev)
static int pci_pm_poweroff(struct device *dev)
{
struct pci_dev *pci_dev = to_pci_dev(dev);
struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
if (pci_has_legacy_pm_support(pci_dev))
return pci_legacy_suspend(dev, PMSG_HIBERNATE);
@ -872,7 +872,7 @@ static int pci_pm_restore_noirq(struct device *dev)
static int pci_pm_restore(struct device *dev)
{
struct pci_dev *pci_dev = to_pci_dev(dev);
struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
int error = 0;
/*
@ -910,7 +910,7 @@ static int pci_pm_restore(struct device *dev)
#endif /* !CONFIG_HIBERNATION */
struct dev_pm_ops pci_dev_pm_ops = {
const struct dev_pm_ops pci_dev_pm_ops = {
.prepare = pci_pm_prepare,
.complete = pci_pm_complete,
.suspend = pci_pm_suspend,

View file

@ -62,7 +62,7 @@ struct bus_type {
int (*suspend)(struct device *dev, pm_message_t state);
int (*resume)(struct device *dev);
struct dev_pm_ops *pm;
const struct dev_pm_ops *pm;
struct bus_type_private *p;
};
@ -132,7 +132,7 @@ struct device_driver {
int (*resume) (struct device *dev);
struct attribute_group **groups;
struct dev_pm_ops *pm;
const struct dev_pm_ops *pm;
struct driver_private *p;
};
@ -200,7 +200,8 @@ struct class {
int (*suspend)(struct device *dev, pm_message_t state);
int (*resume)(struct device *dev);
struct dev_pm_ops *pm;
const struct dev_pm_ops *pm;
struct class_private *p;
};
@ -291,7 +292,7 @@ struct device_type {
char *(*nodename)(struct device *dev);
void (*release)(struct device *dev);
struct dev_pm_ops *pm;
const struct dev_pm_ops *pm;
};
/* interface for exporting device attributes */

View file

@ -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 {

View 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 */

View file

@ -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 */

View file

@ -44,6 +44,7 @@ struct ps2dev {
void ps2_init(struct ps2dev *ps2dev, struct serio *serio);
int ps2_sendbyte(struct ps2dev *ps2dev, unsigned char byte, int timeout);
void ps2_drain(struct ps2dev *ps2dev, int maxbytes, int timeout);
int __ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command);
int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command);
int ps2_handle_ack(struct ps2dev *ps2dev, unsigned char data);
int ps2_handle_response(struct ps2dev *ps2dev, unsigned char data);

View file

@ -31,8 +31,6 @@ struct serio {
bool manual_bind;
bool registered; /* port has been fully registered with driver core */
bool suspended; /* port is suspended */
struct serio_device_id id;

View file

@ -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 */
};