diff options
52 files changed, 3170 insertions, 1076 deletions
diff --git a/Documentation/input/sentelic.txt b/Documentation/input/sentelic.txt new file mode 100644 index 00000000000..f7160a2fb6a --- /dev/null +++ b/Documentation/input/sentelic.txt @@ -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 diff --git a/arch/arm/mach-pxa/include/mach/pxa27x_keypad.h b/arch/arm/mach-pxa/include/mach/pxa27x_keypad.h index d5a48a96dea..63e8965ad85 100644 --- a/arch/arm/mach-pxa/include/mach/pxa27x_keypad.h +++ b/arch/arm/mach-pxa/include/mach/pxa27x_keypad.h @@ -2,6 +2,7 @@ #define __ASM_ARCH_PXA27x_KEYPAD_H #include <linux/input.h> +#include <linux/input/matrix_keypad.h> #define MAX_MATRIX_KEY_ROWS (8) #define MAX_MATRIX_KEY_COLS (8) @@ -51,8 +52,6 @@ struct pxa27x_keypad_platform_data { unsigned int debounce_interval; }; -#define KEY(row, col, val) (((row) << 28) | ((col) << 24) | (val)) - extern void pxa_set_keypad_info(struct pxa27x_keypad_platform_data *info); #endif /* __ASM_ARCH_PXA27x_KEYPAD_H */ diff --git a/arch/arm/mach-w90x900/include/mach/w90p910_keypad.h b/arch/arm/mach-w90x900/include/mach/w90p910_keypad.h new file mode 100644 index 00000000000..556778e8dda --- /dev/null +++ b/arch/arm/mach-w90x900/include/mach/w90p910_keypad.h @@ -0,0 +1,15 @@ +#ifndef __ASM_ARCH_W90P910_KEYPAD_H +#define __ASM_ARCH_W90P910_KEYPAD_H + +#include <linux/input/matrix_keypad.h> + +extern void mfp_set_groupi(struct device *dev); + +struct w90p910_keypad_platform_data { + const struct matrix_keymap_data *keymap_data; + + unsigned int prescale; + unsigned int debounce; +}; + +#endif /* __ASM_ARCH_W90P910_KEYPAD_H */ diff --git a/arch/blackfin/include/asm/bfin_rotary.h b/arch/blackfin/include/asm/bfin_rotary.h new file mode 100644 index 00000000000..425ece64fd5 --- /dev/null +++ b/arch/blackfin/include/asm/bfin_rotary.h @@ -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 diff --git a/drivers/base/platform.c b/drivers/base/platform.c index 456594bd97b..0b111e8e444 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -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, diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 58a3e572f2c..1b1a786b7de 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -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; diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c index f155ad8cdae..2388cf578a6 100644 --- a/drivers/input/joystick/xpad.c +++ b/drivers/input/joystick/xpad.c @@ -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 */ { } }; diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index a6b989a9dc0..50e407de8a7 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig @@ -187,7 +187,7 @@ config KEYBOARD_HIL_OLD submenu. config KEYBOARD_HIL - tristate "HP HIL keyboard support" + tristate "HP HIL keyboard/pointer support" depends on GSC || HP300 default y select HP_SDC @@ -196,7 +196,8 @@ config KEYBOARD_HIL help The "Human Interface Loop" is a older, 8-channel USB-like controller used in several Hewlett Packard models. - This driver implements support for HIL-keyboards attached + This driver implements support for HIL-keyboards and pointing + devices (mice, tablets, touchscreens) attached to your machine, so normally you should say Y here. config KEYBOARD_HP6XX @@ -361,4 +362,14 @@ config KEYBOARD_XTKBD To compile this driver as a module, choose M here: the module will be called xtkbd. +config KEYBOARD_W90P910 + tristate "W90P910 Matrix Keypad support" + depends on ARCH_W90X900 + help + Say Y here to enable the matrix keypad on evaluation board + based on W90P910. + + To compile this driver as a module, choose M here: the + module will be called w90p910_keypad. + endif diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile index b5b5eae9724..15230302920 100644 --- a/drivers/input/keyboard/Makefile +++ b/drivers/input/keyboard/Makefile @@ -31,3 +31,4 @@ obj-$(CONFIG_KEYBOARD_STOWAWAY) += stowaway.o obj-$(CONFIG_KEYBOARD_SUNKBD) += sunkbd.o obj-$(CONFIG_KEYBOARD_TOSA) += tosakbd.o obj-$(CONFIG_KEYBOARD_XTKBD) += xtkbd.o +obj-$(CONFIG_KEYBOARD_W90P910) += w90p910_keypad.o diff --git a/drivers/input/keyboard/bf54x-keys.c b/drivers/input/keyboard/bf54x-keys.c index d427f322e20..fe376a27fe5 100644 --- a/drivers/input/keyboard/bf54x-keys.c +++ b/drivers/input/keyboard/bf54x-keys.c @@ -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: diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c index efed0c9e242..a88aff3816a 100644 --- a/drivers/input/keyboard/gpio_keys.c +++ b/drivers/input/keyboard/gpio_keys.c @@ -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 } }; diff --git a/drivers/input/keyboard/hil_kbd.c b/drivers/input/keyboard/hil_kbd.c index 6f356705ee3..c83f4b2ec7d 100644 --- a/drivers/input/keyboard/hil_kbd.c +++ b/drivers/input/keyboard/hil_kbd.c @@ -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) { - struct input_dev *dev = kbd->dev; - hil_packet *data = kbd->data; - hil_packet p; - int idx, i, cnt; + if ((p & ~HIL_CMDCT_POL) == (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_POL)) + return false; - idx = kbd->idx4/4; - p = data[idx - 1]; + if ((p & ~HIL_CMDCT_RPL) == (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_RPL)) + return false; - if ((p & ~HIL_CMDCT_POL) == - (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_POL)) - goto report; - if ((p & ~HIL_CMDCT_RPL) == - (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_RPL)) - goto report; + return true; +} + +static void hil_dev_handle_command_response(struct hil_dev *dev) +{ + hil_packet p; + char *buf; + int i, idx; + + idx = dev->idx4 / 4; + p = dev->data[idx - 1]; - /* Not a poll response. See if we are loading config records. */ switch (p & HIL_PKT_DATA_MASK) { case HIL_CMD_IDD: - for (i = 0; i < idx; i++) - kbd->idd[i] = kbd->data[i] & HIL_PKT_DATA_MASK; - for (; i < HIL_KBD_MAX_LENGTH; i++) - kbd->idd[i] = 0; + buf = dev->idd; break; case HIL_CMD_RSC: - for (i = 0; i < idx; i++) - kbd->rsc[i] = kbd->data[i] & HIL_PKT_DATA_MASK; - for (; i < HIL_KBD_MAX_LENGTH; i++) - kbd->rsc[i] = 0; + buf = dev->rsc; break; case HIL_CMD_EXD: - for (i = 0; i < idx; i++) - kbd->exd[i] = kbd->data[i] & HIL_PKT_DATA_MASK; - for (; i < HIL_KBD_MAX_LENGTH; i++) - kbd->exd[i] = 0; + buf = dev->exd; break; case HIL_CMD_RNM: - for (i = 0; i < idx; i++) - kbd->rnm[i] = kbd->data[i] & HIL_PKT_DATA_MASK; - for (; i < HIL_KBD_MAX_LENGTH + 1; i++) - kbd->rnm[i] = '\0'; + dev->rnm[HIL_PACKET_MAX_LENGTH] = 0; + buf = dev->rnm; break; default: /* These occur when device isn't present */ - if (p == (HIL_ERR_INT | HIL_PKT_CMD)) - break; - /* Anything else we'd like to know about. */ - printk(KERN_WARNING PREFIX "Device sent unknown record %x\n", p); - break; + if (p != (HIL_ERR_INT | HIL_PKT_CMD)) { + /* Anything else we'd like to know about. */ + printk(KERN_WARNING PREFIX "Device sent unknown record %x\n", p); + } + goto out; } - goto out; - report: - cnt = 1; + for (i = 0; i < idx; i++) + buf[i] = dev->data[i] & HIL_PKT_DATA_MASK; + for (; i < HIL_PACKET_MAX_LENGTH; i++) + buf[i] = 0; + out: + complete(&dev->cmd_done); +} + +static void hil_dev_handle_kbd_events(struct hil_dev *kbd) +{ + struct input_dev *dev = kbd->dev; + int idx = kbd->idx4 / 4; + int i; + switch (kbd->data[0] & HIL_POL_CHARTYPE_MASK) { case HIL_POL_CHARTYPE_NONE: - break; + return; case HIL_POL_CHARTYPE_ASCII: - while (cnt < idx - 1) - input_report_key(dev, kbd->data[cnt++] & 0x7f, 1); + for (i = 1; i < idx - 1; i++) + input_report_key(dev, kbd->data[i] & 0x7f, 1); break; case HIL_POL_CHARTYPE_RSVD1: case HIL_POL_CHARTYPE_RSVD2: case HIL_POL_CHARTYPE_BINARY: - while (cnt < idx - 1) - input_report_key(dev, kbd->data[cnt++], 1); + for (i = 1; i < idx - 1; i++) + input_report_key(dev, kbd->data[i], 1); break; case HIL_POL_CHARTYPE_SET1: - while (cnt < idx - 1) { - unsigned int key; - int up; - key = kbd->data[cnt++]; - up = key & HIL_KBD_SET1_UPBIT; + for (i = 1; i < idx - 1; i++) { + unsigned int key = kbd->data[i]; + int up = key & HIL_KBD_SET1_UPBIT; + key &= (~HIL_KBD_SET1_UPBIT & 0xff); key = hil_kbd_set1[key >> HIL_KBD_SET1_SHIFT]; - if (key != KEY_RESERVED) - input_report_key(dev, key, !up); + input_report_key(dev, key, !up); } break; case HIL_POL_CHARTYPE_SET2: - while (cnt < idx - 1) { - unsigned int key; - int up; - key = kbd->data[cnt++]; - up = key & HIL_KBD_SET2_UPBIT; + for (i = 1; i < idx - 1; i++) { + unsigned int key = kbd->data[i]; + int up = key & HIL_KBD_SET2_UPBIT; + key &= (~HIL_KBD_SET1_UPBIT & 0xff); key = key >> HIL_KBD_SET2_SHIFT; - if (key != KEY_RESERVED) - input_report_key(dev, key, !up); + input_report_key(dev, key, !up); } break; case HIL_POL_CHARTYPE_SET3: - while (cnt < idx - 1) { - unsigned int key; - int up; - key = kbd->data[cnt++]; - up = key & HIL_KBD_SET3_UPBIT; + for (i = 1; i < idx - 1; i++) { + unsigned int key = kbd->data[i]; + int up = key & HIL_KBD_SET3_UPBIT; + key &= (~HIL_KBD_SET1_UPBIT & 0xff); key = hil_kbd_set3[key >> HIL_KBD_SET3_SHIFT]; - if (key != KEY_RESERVED) - input_report_key(dev, key, !up); + input_report_key(dev, key, !up); } break; } - out: - kbd->idx4 = 0; - up(&kbd->sem); + + input_sync(dev); } -static void hil_kbd_process_err(struct hil_kbd *kbd) +static void hil_dev_handle_ptr_events(struct hil_dev *ptr) +{ + struct input_dev *dev = ptr->dev; + int idx = ptr->idx4 / 4; + hil_packet p = ptr->data[idx - 1]; + int i, cnt, laxis; + bool absdev, ax16; + + if ((p & HIL_CMDCT_POL) != idx - 1) { + printk(KERN_WARNING PREFIX + "Malformed poll packet %x (idx = %i)\n", p, idx); + return; + } + + i = (p & HIL_POL_AXIS_ALT) ? 3 : 0; + laxis = (p & HIL_POL_NUM_AXES_MASK) + i; + + ax16 = ptr->idd[1] & HIL_IDD_HEADER_16BIT; /* 8 or 16bit resolution */ + absdev = ptr->idd[1] & HIL_IDD_HEADER_ABS; + + for (cnt = 1; i < laxis; i++) { + unsigned int lo, hi, val; + + lo = ptr->data[cnt++] & HIL_PKT_DATA_MASK; + hi = ax16 ? (ptr->data[cnt++] & HIL_PKT_DATA_MASK) : 0; + + if (absdev) { + val = lo + (hi << 8); +#ifdef TABLET_AUTOADJUST + if (val < dev->absmin[ABS_X + i]) + dev->absmin[ABS_X + i] = val; + if (val > dev->absmax[ABS_X + i]) + dev->absmax[ABS_X + i] = val; +#endif + if (i%3) val = dev->absmax[ABS_X + i] - val; + input_report_abs(dev, ABS_X + i, val); + } else { + val = (int) (((int8_t)lo) | ((int8_t)hi << 8)); + if (i % 3) + val *= -1; + input_report_rel(dev, REL_X + i, val); + } + } + + while (cnt < idx - 1) { + unsigned int btn = ptr->data[cnt++]; + int up = btn & 1; + + btn &= 0xfe; + if (btn == 0x8e) + continue; /* TODO: proximity == touch? */ + if (btn > 0x8c || btn < 0x80) + continue; + btn = (btn - 0x80) >> 1; + btn = ptr->btnmap[btn]; + input_report_key(dev, btn, !up); + } + + input_sync(dev); +} + +static void hil_dev_process_err(struct hil_dev *dev) { printk(KERN_WARNING PREFIX "errored HIL packet\n"); - kbd->idx4 = 0; - up(&kbd->sem); + dev->idx4 = 0; + complete(&dev->cmd_done); /* just in case somebody is waiting */ } -static irqreturn_t hil_kbd_interrupt(struct serio *serio, +static irqreturn_t hil_dev_interrupt(struct serio *serio, unsigned char data, unsigned int flags) { - struct hil_kbd *kbd; + struct hil_dev *dev; hil_packet packet; int idx; - kbd = serio_get_drvdata(serio); - BUG_ON(kbd == NULL); + dev = serio_get_drvdata(serio); + BUG_ON(dev == NULL); - if (kbd->idx4 >= (HIL_KBD_MAX_LENGTH * sizeof(hil_packet))) { - hil_kbd_process_err(kbd); - return IRQ_HANDLED; + if (dev->idx4 >= HIL_PACKET_MAX_LENGTH * sizeof(hil_packet)) { + hil_dev_process_err(dev); + goto out; } - idx = kbd->idx4/4; - if (!(kbd->idx4 % 4)) - kbd->data[idx] = 0; - packet = kbd->data[idx]; - packet |= ((hil_packet)data) << ((3 - (kbd->idx4 % 4)) * 8); - kbd->data[idx] = packet; + + idx = dev->idx4 / 4; + if (!(dev->idx4 % 4)) + dev->data[idx] = 0; + packet = dev->data[idx]; + packet |= ((hil_packet)data) << ((3 - (dev->idx4 % 4)) * 8); + dev->data[idx] = packet; /* Records of N 4-byte hil_packets must terminate with a command. */ - if ((++(kbd->idx4)) % 4) - return IRQ_HANDLED; - if ((packet & 0xffff0000) != HIL_ERR_INT) { - hil_kbd_process_err(kbd); - return IRQ_HANDLED; + if ((++dev->idx4 % 4) == 0) { + if ((packet & 0xffff0000) != HIL_ERR_INT) { + hil_dev_process_err(dev); + } else if (packet & HIL_PKT_CMD) { + if (hil_dev_is_command_response(packet)) + hil_dev_handle_command_response(dev); + else if (dev->is_pointer) + hil_dev_handle_ptr_events(dev); + else + hil_dev_handle_kbd_events(dev); + dev->idx4 = 0; + } } - if (packet & HIL_PKT_CMD) - hil_kbd_process_record(kbd); + out: return IRQ_HANDLED; } -static void hil_kbd_disconnect(struct serio *serio) +static void hil_dev_disconnect(struct serio *serio) { - struct hil_kbd *kbd; + struct hil_dev *dev = serio_get_drvdata(serio); - kbd = serio_get_drvdata(serio); - BUG_ON(kbd == NULL); + BUG_ON(dev == NULL); serio_close(serio); - input_unregister_device(kbd->dev); - kfree(kbd); + input_unregister_device(dev->dev); + serio_set_drvdata(serio, NULL); + kfree(dev); +} + +static void hil_dev_keyboard_setup(struct hil_dev *kbd) +{ + struct input_dev *input_dev = kbd->dev; + uint8_t did = kbd->idd[0]; + int i; + + input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP); + input_dev->ledbit[0] = BIT_MASK(LED_NUML) | BIT_MASK(LED_CAPSL) | + BIT_MASK(LED_SCROLLL); + + for (i = 0; i < 128; i++) { + __set_bit(hil_kbd_set1[i], input_dev->keybit); + __set_bit(hil_kbd_set3[i], input_dev->keybit); + } + __clear_bit(KEY_RESERVED, input_dev->keybit); + + input_dev->keycodemax = HIL_KEYCODES_SET1_TBLSIZE; + input_dev->keycodesize = sizeof(hil_kbd_set1[0]); + input_dev->keycode = hil_kbd_set1; + + input_dev->name = strlen(kbd->rnm) ? kbd->rnm : "HIL keyboard"; + input_dev->phys = "hpkbd/input0"; + + printk(KERN_INFO PREFIX "HIL keyboard found (did = 0x%02x, lang = %s)\n", + did, hil_language[did & HIL_IDD_DID_TYPE_KB_LANG_MASK]); } -static int hil_kbd_connect(struct serio *serio, struct serio_driver *drv) +static void hil_dev_pointer_setup(struct hil_dev *ptr) { - struct hil_kbd *kbd; - uint8_t did, *idd; - int i; + struct input_dev *input_dev = ptr->dev; + uint8_t did = ptr->idd[0]; + uint8_t *idd = ptr->idd + 1; + unsigned int naxsets = HIL_IDD_NUM_AXSETS(*idd); + unsigned int i, btntype; + const char *txt; + + ptr->naxes = HIL_IDD_NUM_AXES_PER_SET(*idd); + + switch (did & HIL_IDD_DID_TYPE_MASK) { + case HIL_IDD_DID_TYPE_REL: + input_dev->evbit[0] = BIT_MASK(EV_REL); - kbd = kzalloc(sizeof(*kbd), GFP_KERNEL); - if (!kbd) - return -ENOMEM; + for (i = 0; i < ptr->naxes; i++) + __set_bit(REL_X + i, input_dev->relbit); - kbd->dev = input_allocate_device(); - if (!kbd->dev) + for (i = 3; naxsets > 1 && i < ptr->naxes + 3; i++) + __set_bit(REL_X + i, input_dev->relbit); + + txt = "relative"; + break; + + case HIL_IDD_DID_TYPE_ABS: + input_dev->evbit[0] = BIT_MASK(EV_ABS); + + for (i = 0; i < ptr->naxes; i++) + input_set_abs_params(input_dev, ABS_X + i, + 0, HIL_IDD_AXIS_MAX(idd, i), 0, 0); + + for (i = 3; naxsets > 1 && i < ptr->naxes + 3; i++) + input_set_abs_params(input_dev, ABS_X + i, + 0, HIL_IDD_AXIS_MAX(idd, i - 3), 0, 0); + +#ifdef TABLET_AUTOADJUST + for (i = 0; i < ABS_MAX; i++) { + int diff = input_dev->absmax[ABS_X + i] / 10; + input_dev->absmin[ABS_X + i] += diff; + input_dev->absmax[ABS_X + i] -= diff; + } +#endif + + txt = "absolute"; + break; + + default: + BUG(); + } + + ptr->nbtn = HIL_IDD_NUM_BUTTONS(idd); + if (ptr->nbtn) + input_dev->evbit[0] |= BIT_MASK(EV_KEY); + + btntype = BTN_MISC; + if ((did & HIL_IDD_DID_ABS_TABLET_MASK) == HIL_IDD_DID_ABS_TABLET) +#ifdef TABLET_SIMULATES_MOUSE + btntype = BTN_TOUCH; +#else + btntype = BTN_DIGI; +#endif + if ((did & HIL_IDD_DID_ABS_TSCREEN_MASK) == HIL_IDD_DID_ABS_TSCREEN) + btntype = BTN_TOUCH; + + if ((did & HIL_IDD_DID_REL_MOUSE_MASK) == HIL_IDD_DID_REL_MOUSE) + btntype = BTN_MOUSE; + + for (i = 0; i < ptr->nbtn; i++) { + __set_bit(btntype | i, input_dev->keybit); + ptr->btnmap[i] = btntype | i; + } + + if (btntype == BTN_MOUSE) { + /* Swap buttons 2 and 3 */ + ptr->btnmap[1] = BTN_MIDDLE; + ptr->btnmap[2] = BTN_RIGHT; + } + + input_dev->name = strlen(ptr->rnm) ? ptr->rnm : "HIL pointer device"; + + printk(KERN_INFO PREFIX + "HIL pointer device found (did: 0x%02x, axis: %s)\n", + did, txt); + printk(KERN_INFO PREFIX + "HIL pointer has %i buttons and %i sets of %i axes\n", + ptr->nbtn, naxsets, ptr->naxes); +} + +static int hil_dev_connect(struct serio *serio, struct serio_driver *drv) +{ + struct hil_dev *dev; + struct input_dev *input_dev; + uint8_t did, *idd; + int error; + + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!dev || !input_dev) { + error = -ENOMEM; goto bail0; + } - if (serio_open(serio, drv)) - goto bail1; + dev->serio = serio; + dev->dev = input_dev; - serio_set_drvdata(serio, kbd); - kbd->serio = serio; + error = serio_open(serio, drv); + if (error) + goto bail0; - init_MUTEX_LOCKED(&kbd->sem); + serio_set_drvdata(serio, dev); /* Get device info. MLC driver supplies devid/status/etc. */ - serio->write(serio, 0); - serio->write(serio, 0); - serio->write(serio, HIL_PKT_CMD >> 8); - serio->write(serio, HIL_CMD_IDD); - down(&kbd->sem); - - serio->write(serio, 0); - serio->write(serio, 0); - serio->write(serio, HIL_PKT_CMD >> 8); - serio->write(serio, HIL_CMD_RSC); - down(&kbd->sem); - - serio->write(serio, 0); - serio->write(serio, 0); - serio->write(serio, HIL_PKT_CMD >> 8); - serio->write(serio, HIL_CMD_RNM); - down(&kbd->sem); - - serio->write(serio, 0); - serio->write(serio, 0); - serio->write(serio, HIL_PKT_CMD >> 8); - serio->write(serio, HIL_CMD_EXD); - down(&kbd->sem); - - up(&kbd->sem); - - did = kbd->idd[0]; - idd = kbd->idd + 1; + init_completion(&dev->cmd_done); + serio_write(serio, 0); + serio_write(serio, 0); + serio_write(serio, HIL_PKT_CMD >> 8); + serio_write(serio, HIL_CMD_IDD); + error = wait_for_completion_killable(&dev->cmd_done); + if (error) + goto bail1; + + init_completion(&dev->cmd_done); + serio_write(serio, 0); + serio_write(serio, 0); + serio_write(serio, HIL_PKT_CMD >> 8); + serio_write(serio, HIL_CMD_RSC); + error = wait_for_completion_killable(&dev->cmd_done); + if (error) + goto bail1; + + init_completion(&dev->cmd_done); + serio_write(serio, 0); + serio_write(serio, 0); + serio_write(serio, HIL_PKT_CMD >> 8); + serio_write(serio, HIL_CMD_RNM); + error = wait_for_completion_killable(&dev->cmd_done); + if (error) + goto bail1; + + init_completion(&dev->cmd_done); + serio_write(serio, 0); + serio_write(serio, 0); + serio_write(serio, HIL_PKT_CMD >> 8); + serio_write(serio, HIL_CMD_EXD); + error = wait_for_completion_killable(&dev->cmd_done); + if (error) + goto bail1; + + did = dev->idd[0]; + idd = dev->idd + 1; + switch (did & HIL_IDD_DID_TYPE_MASK) { case HIL_IDD_DID_TYPE_KB_INTEGRAL: case HIL_IDD_DID_TYPE_KB_ITF: case HIL_IDD_DID_TYPE_KB_RSVD: case HIL_IDD_DID_TYPE_CHAR: - printk(KERN_INFO PREFIX "HIL keyboard found (did = 0x%02x, lang = %s)\n", - did, hil_language[did & HIL_IDD_DID_TYPE_KB_LANG_MASK]); - break; - default: - goto bail2; - } + if (HIL_IDD_NUM_BUTTONS(idd) || + HIL_IDD_NUM_AXES_PER_SET(*idd)) { + printk(KERN_INFO PREFIX + "combo devices are not supported.\n"); + goto bail1; + } - if (HIL_IDD_NUM_BUTTONS(idd) || HIL_IDD_NUM_AXES_PER_SET(*idd)) { - printk(KERN_INFO PREFIX "keyboards only, no combo devices supported.\n"); - goto bail2; - } + dev->is_pointer = false; + hil_dev_keyboard_setup(dev); + break; - kbd->dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP); - kbd->dev->ledbit[0] = BIT_MASK(LED_NUML) | BIT_MASK(LED_CAPSL) | - BIT_MASK(LED_SCROLLL); - kbd->dev->keycodemax = HIL_KEYCODES_SET1_TBLSIZE; - kbd->dev->keycodesize = sizeof(hil_kbd_set1[0]); - kbd->dev->keycode = hil_kbd_set1; - kbd->dev->name = strlen(kbd->rnm) ? kbd->rnm : HIL_GENERIC_NAME; - kbd->dev->phys = "hpkbd/input0"; /* XXX */ - - kbd->dev->id.bustype = BUS_HIL; - kbd->dev->id.vendor = PCI_VENDOR_ID_HP; - kbd->dev->id.product = 0x0001; /* TODO: get from kbd->rsc */ - kbd->dev->id.version = 0x0100; /* TODO: get from kbd->rsc */ - kbd->dev->dev.parent = &serio->dev; + case HIL_IDD_DID_TYPE_REL: + case HIL_IDD_DID_TYPE_ABS: + dev->is_pointer = true; + hil_dev_pointer_setup(dev); + break; - for (i = 0; i < 128; i++) { - set_bit(hil_kbd_set1[i], kbd->dev->keybit); - set_bit(hil_kbd_set3[i], kbd->dev->keybit); + default: + goto bail1; } - clear_bit(0, kbd->dev->keybit); - input_register_device(kbd->dev); - printk(KERN_INFO "input: %s, ID: %d\n", - kbd->dev->name, did); + input_dev->id.bustype = BUS_HIL; + input_dev->id.vendor = PCI_VENDOR_ID_HP; + input_dev->id.product = 0x0001; /* TODO: get from kbd->rsc */ + input_dev->id.version = 0x0100; /* TODO: get from kbd->rsc */ + input_dev->dev.parent = &serio->dev; + + if (!dev->is_pointer) { + serio_write(serio, 0); + serio_write(serio, 0); + serio_write(serio, HIL_PKT_CMD >> 8); + /* Enable Keyswitch Autorepeat 1 */ + serio_write(serio, HIL_CMD_EK1); + /* No need to wait for completion */ + } - serio->write(serio, 0); - serio->write(serio, 0); - serio->write(serio, HIL_PKT_CMD >> 8); - serio->write(serio, HIL_CMD_EK1); /* Enable Keyswitch Autorepeat 1 */ - down(&kbd->sem); - up(&kbd->sem); + error = input_register_device(input_dev); + if (error) + goto bail1; return 0; - bail2: + + bail1: serio_close(serio); serio_set_drvdata(serio, NULL); - bail1: - input_free_device(kbd->dev); bail0: - kfree(kbd); - return -EIO; + input_free_device(input_dev); + kfree(dev); + return error; } -static struct serio_device_id hil_kbd_ids[] = { +static struct serio_device_id hil_dev_ids[] = { { .type = SERIO_HIL_MLC, .proto = SERIO_HIL, @@ -378,26 +567,26 @@ static struct serio_device_id hil_kbd_ids[] = { { 0 } }; -static struct serio_driver hil_kbd_serio_drv = { +static struct serio_driver hil_serio_drv = { .driver = { - .name = "hil_kbd", + .name = "hil_dev", }, - .description = "HP HIL keyboard driver", - .id_table = hil_kbd_ids, - .connect = hil_kbd_connect, - .disconnect = hil_kbd_disconnect, - .interrupt = hil_kbd_interrupt + .description = "HP HIL keyboard/mouse/tablet driver", + .id_table = hil_dev_ids, + .connect = hil_dev_connect, + .disconnect = hil_dev_disconnect, + .interrupt = hil_dev_interrupt }; -static int __init hil_kbd_init(void) +static int __init hil_dev_init(void) { - return serio_register_driver(&hil_kbd_serio_drv); + return serio_register_driver(&hil_serio_drv); } -static void __exit hil_kbd_exit(void) +static void __exit hil_dev_exit(void) { - serio_unregister_driver(&hil_kbd_serio_drv); + serio_unregister_driver(&hil_serio_drv); } -module_init(hil_kbd_init); -module_exit(hil_kbd_exit); +module_init(hil_dev_init); +module_exit(hil_dev_exit); diff --git a/drivers/input/keyboard/lkkbd.c b/drivers/input/keyboard/lkkbd.c index 4730ef35c73..f9847e0fb55 100644 --- a/drivers/input/keyboard/lkkbd.c +++ b/drivers/input/keyboard/lkkbd.c @@ -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; diff --git a/drivers/input/keyboard/pxa27x_keypad.c b/drivers/input/keyboard/pxa27x_keypad.c index 0d2fc64a5e1..c987cc75674 100644 --- a/drivers/input/keyboard/pxa27x_keypad.c +++ b/drivers/input/keyboard/pxa27x_keypad.c @@ -25,6 +25,7 @@ #include <linux/platform_device.h> #include <linux/clk.h> #include <linux/err.h> +#include <linux/input/matrix_keypad.h> #include <asm/mach/arch.h> #include <asm/mach/map.h> @@ -107,7 +108,7 @@ struct pxa27x_keypad { int irq; /* matrix key code map */ - unsigned int matrix_keycodes[MAX_MATRIX_KEY_NUM]; + unsigned short matrix_keycodes[MAX_MATRIX_KEY_NUM]; /* state row bits of each column scan */ uint32_t matrix_key_state[MAX_MATRIX_KEY_COLS]; @@ -124,21 +125,21 @@ static void pxa27x_keypad_build_keycode(struct pxa27x_keypad *keypad) { struct pxa27x_keypad_platform_data *pdata = keypad->pdata; struct input_dev *input_dev = keypad->input_dev; - unsigned int *key; int i; - key = &pdata->matrix_key_map[0]; - for (i = 0; i < pdata->matrix_key_map_size; i++, key++) { - int row = ((*key) >> 28) & 0xf; - int col = ((*key) >> 24) & 0xf; - int code = (*key) & 0xffffff; + for (i = 0; i < pdata->matrix_key_map_size; i++) { + unsigned int key = pdata->matrix_key_map[i]; + unsigned int row = KEY_ROW(key); + unsigned int col = KEY_COL(key); + unsigned short code = KEY_VAL(key); keypad->matrix_keycodes[(row << 3) + col] = code; - set_bit(code, input_dev->keybit); + __set_bit(code, input_dev->keybit); } + __clear_bit(KEY_RESERVED, input_dev->keybit); for (i = 0; i < pdata->direct_key_num; i++) - set_bit(pdata->direct_key_map[i], input_dev->keybit); + __set_bit(pdata->direct_key_map[i], input_dev->keybit); keypad->rotary_up_key[0] = pdata->rotary0_up_key; keypad->rotary_up_key[1] = pdata->rotary1_up_key; @@ -149,18 +150,18 @@ static void pxa27x_keypad_build_keycode(struct pxa27x_keypad *keypad) if (pdata->enable_rotary0) { if (pdata->rotary0_up_key && pdata->rotary0_down_key) { - set_bit(pdata->rotary0_up_key, input_dev->keybit); - set_bit(pdata->rotary0_down_key, input_dev->keybit); + __set_bit(pdata->rotary0_up_key, input_dev->keybit); + __set_bit(pdata->rotary0_down_key, input_dev->keybit); } else - set_bit(pdata->rotary0_rel_code, input_dev->relbit); + __set_bit(pdata->rotary0_rel_code, input_dev->relbit); } if (pdata->enable_rotary1) { if (pdata->rotary1_up_key && pdata->rotary1_down_key) { - set_bit(pdata->rotary1_up_key, input_dev->keybit); - set_bit(pdata->rotary1_down_key, input_dev->keybit); + __set_bit(pdata->rotary1_up_key, input_dev->keybit); + __set_bit(pdata->rotary1_down_key, input_dev->keybit); } else - set_bit(pdata->rotary1_rel_code, input_dev->relbit); + __set_bit(pdata->rotary1_rel_code, input_dev->relbit); } } @@ -388,8 +389,9 @@ static void pxa27x_keypad_close(struct input_dev *dev) } #ifdef CONFIG_PM -static int pxa27x_keypad_suspend(struct platform_device *pdev, pm_message_t state) +static int pxa27x_keypad_suspend(struct device *dev) { + struct platform_device *pdev = to_platform_device(dev); struct pxa27x_keypad *keypad = platform_get_drvdata(pdev); clk_disable(keypad->clk); @@ -400,8 +402,9 @@ static int pxa27x_keypad_suspend(struct platform_device *pdev, pm_message_t stat return 0; } -static int pxa27x_keypad_resume(struct platform_device *pdev) +static int pxa27x_keypad_resume(struct device *dev) { + struct platform_device *pdev = to_platform_device(dev); struct pxa27x_keypad *keypad = platform_get_drvdata(pdev); struct input_dev *input_dev = keypad->input_dev; @@ -420,12 +423,12 @@ static int pxa27x_keypad_resume(struct platform_device *pdev) return 0; } -#else -#define pxa27x_keypad_suspend NULL -#define pxa27x_keypad_resume NULL -#endif -#define res_size(res) ((res)->end - (res)->start + 1) +static const struct dev_pm_ops pxa27x_keypad_pm_ops = { + .suspend = pxa27x_keypad_suspend, + .resume = pxa27x_keypad_resume, +}; +#endif static int __devinit pxa27x_keypad_probe(struct platform_device *pdev) { @@ -461,14 +464,14 @@ static int __devinit pxa27x_keypad_probe(struct platform_device *pdev) goto failed_free; } - res = request_mem_region(res->start, res_size(res), pdev->name); + res = request_mem_region(res->start, resource_size(res), pdev->name); if (res == NULL) { dev_err(&pdev->dev, "failed to request I/O memory\n"); error = -EBUSY; goto failed_free; } - keypad->mmio_base = ioremap(res->start, res_size(res)); + keypad->mmio_base = ioremap(res->start, resource_size(res)); if (keypad->mmio_base == NULL) { dev_err(&pdev->dev, "failed to remap I/O memory\n"); error = -ENXIO; @@ -540,7 +543,7 @@ failed_put_clk: failed_free_io: iounmap(keypad->mmio_base); failed_free_mem: - release_mem_region(res->start, res_size(res)); + release_mem_region(res->start, resource_size(res)); failed_free: kfree(keypad); return error; @@ -552,8 +555,6 @@ static int __devexit pxa27x_keypad_remove(struct platform_device *pdev) struct resource *res; free_irq(keypad->irq, pdev); - - clk_disable(keypad->clk); clk_put(keypad->clk); input_unregister_device(keypad->input_dev); @@ -562,7 +563,7 @@ static int __devexit pxa27x_keypad_remove(struct platform_device *pdev) iounmap(keypad->mmio_base); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - release_mem_region(res->start, res_size(res)); + release_mem_region(res->start, resource_size(res)); platform_set_drvdata(pdev, NULL); kfree(keypad); @@ -575,11 +576,12 @@ MODULE_ALIAS("platform:pxa27x-keypad"); static struct platform_driver pxa27x_keypad_driver = { .probe = pxa27x_keypad_probe, .remove = __devexit_p(pxa27x_keypad_remove), - .suspend = pxa27x_keypad_suspend, - .resume = pxa27x_keypad_resume, .driver = { .name = "pxa27x-keypad", .owner = THIS_MODULE, +#ifdef CONFIG_PM + .pm = &pxa27x_keypad_pm_ops, +#endif }, }; diff --git a/drivers/input/keyboard/sh_keysc.c b/drivers/input/keyboard/sh_keysc.c index cea70e6a103..0714bf2c28f 100644 --- a/drivers/input/keyboard/sh_keysc.c +++ b/drivers/input/keyboard/sh_keysc.c @@ -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; } diff --git a/drivers/input/keyboard/sunkbd.c b/drivers/input/keyboard/sunkbd.c index 9fce6d1e29b..e7aa935a294 100644 --- a/drivers/input/keyboard/sunkbd.c +++ b/drivers/input/keyboard/sunkbd.c @@ -150,8 +150,8 @@ static int sunkbd_event(struct input_dev *dev, unsigned int type, unsigned int c case EV_LED: - sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_SETLED); - sunkbd->serio->write(sunkbd->serio, + serio_write(sunkbd->serio, SUNKBD_CMD_SETLED); + serio_write(sunkbd->serio, (!!test_bit(LED_CAPSL, dev->led) << 3) | (!!test_bit(LED_SCROLLL, dev->led) << 2) | (!!test_bit(LED_COMPOSE, dev->led) << 1) | !!test_bit(LED_NUML, dev->led)); return 0; @@ -161,11 +161,11 @@ static int sunkbd_event(struct input_dev *dev, unsigned int type, unsigned int c switch (code) { case SND_CLICK: - sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_NOCLICK - value); + serio_write(sunkbd->serio, SUNKBD_CMD_NOCLICK - value); return 0; case SND_BELL: - sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_BELLOFF - value); + serio_write(sunkbd->serio, SUNKBD_CMD_BELLOFF - value); return 0; } @@ -183,7 +183,7 @@ static int sunkbd_event(struct input_dev *dev, unsigned int type, unsigned int c static int sunkbd_initialize(struct sunkbd *sunkbd) { sunkbd->reset = -2; - sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_RESET); + serio_write(sunkbd->serio, SUNKBD_CMD_RESET); wait_event_interruptible_timeout(sunkbd->wait, sunkbd->reset >= 0, HZ); if (sunkbd->reset < 0) return -1; @@ -192,7 +192,7 @@ static int sunkbd_initialize(struct sunkbd *sunkbd) if (sunkbd->type == 4) { /* Type 4 keyboard */ sunkbd->layout = -2; - sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_LAYOUT); + serio_write(sunkbd->serio, SUNKBD_CMD_LAYOUT); wait_event_interruptible_timeout(sunkbd->wait, sunkbd->layout >= 0, HZ/4); if (sunkbd->layout < 0) return -1; if (sunkbd->layout & SUNKBD_LAYOUT_5_MASK) sunkbd->type = 5; @@ -212,12 +212,14 @@ static void sunkbd_reinit(struct work_struct *work) wait_event_interruptible_timeout(sunkbd->wait, sunkbd->reset >= 0, HZ); - sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_SETLED); - sunkbd->serio->write(sunkbd->serio, - (!!test_bit(LED_CAPSL, sunkbd->dev->led) << 3) | (!!test_bit(LED_SCROLLL, sunkbd->dev->led) << 2) | - (!!test_bit(LED_COMPOSE, sunkbd->dev->led) << 1) | !!test_bit(LED_NUML, sunkbd->dev->led)); - sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_NOCLICK - !!test_bit(SND_CLICK, sunkbd->dev->snd)); - sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_BELLOFF - !!test_bit(SND_BELL, sunkbd->dev->snd)); + serio_write(sunkbd->serio, SUNKBD_CMD_SETLED); + serio_write(sunkbd->serio, + (!!test_bit(LED_CAPSL, sunkbd->dev->led) << 3) | + (!!test_bit(LED_SCROLLL, sunkbd->dev->led) << 2) | + (!!test_bit(LED_COMPOSE, sunkbd->dev->led) << 1) | + !!test_bit(LED_NUML, sunkbd->dev->led)); + serio_write(sunkbd->serio, SUNKBD_CMD_NOCLICK - !!test_bit(SND_CLICK, sunkbd->dev->snd)); + serio_write(sunkbd->serio, SUNKBD_CMD_BELLOFF - !!test_bit(SND_BELL, sunkbd->dev->snd)); } static void sunkbd_enable(struct sunkbd *sunkbd, int enable) diff --git a/drivers/input/keyboard/w90p910_keypad.c b/drivers/input/keyboard/w90p910_keypad.c new file mode 100644 index 00000000000..b8598ae124e --- /dev/null +++ b/drivers/input/keyboard/w90p910_keypad.c @@ -0,0 +1,291 @@ +/* + * Copyright (c) 2008-2009 Nuvoton technology corporation. + * + * Wan ZongShun <mcuos.com@gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation;version 2 of the License. + * + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/input.h> +#include <linux/device.h> +#include <linux/platform_device.h> +#include <linux/clk.h> +#include <linux/err.h> +#include <linux/io.h> + +#include <mach/w90p910_keypad.h> + +/* Keypad Interface Control Registers */ +#define KPI_CONF 0x00 +#define KPI_3KCONF 0x04 +#define KPI_LPCONF 0x08 +#define KPI_STATUS 0x0C + +#define IS1KEY (0x01 << 16) +#define INTTR (0x01 << 21) +#define KEY0R (0x0f << 3) +#define KEY0C 0x07 +#define DEBOUNCE_BIT 0x08 +#define KSIZE0 (0x01 << 16) +#define KSIZE1 (0x01 << 17) +#define KPSEL (0x01 << 19) +#define ENKP (0x01 << 18) + +#define KGET_RAW(n) (((n) & KEY0R) >> 3) +#define KGET_COLUMN(n) ((n) & KEY0C) + +#define W90P910_MAX_KEY_NUM (8 * 8) +#define W90P910_ROW_SHIFT 3 + +struct w90p910_keypad { + const struct w90p910_keypad_platform_data *pdata; + struct clk *clk; + struct input_dev *input_dev; + void __iomem *mmio_base; + int irq; + unsigned short keymap[W90P910_MAX_KEY_NUM]; +}; + +static void w90p910_keypad_scan_matrix(struct w90p910_keypad *keypad, + unsigned int status) +{ + struct input_dev *input_dev = keypad->input_dev; + unsigned int row = KGET_RAW(status); + unsigned int col = KGET_COLUMN(status); + unsigned int code = MATRIX_SCAN_CODE(row, col, W90P910_ROW_SHIFT); + unsigned int key = keypad->keymap[code]; + + input_event(input_dev, EV_MSC, MSC_SCAN, code); + input_report_key(input_dev, key, 1); + input_sync(input_dev); + + input_event(input_dev, EV_MSC, MSC_SCAN, code); + input_report_key(input_dev, key, 0); + input_sync(input_dev); +} + +static irqreturn_t w90p910_keypad_irq_handler(int irq, void *dev_id) +{ + struct w90p910_keypad *keypad = dev_id; + unsigned int kstatus, val; + + kstatus = __raw_readl(keypad->mmio_base + KPI_STATUS); + + val = INTTR | IS1KEY; + + if (kstatus & val) + w90p910_keypad_scan_matrix(keypad, kstatus); + + return IRQ_HANDLED; +} + +static int w90p910_keypad_open(struct input_dev *dev) +{ + struct w90p910_keypad *keypad = input_get_drvdata(dev); + const struct w90p910_keypad_platform_data *pdata = keypad->pdata; + unsigned int val, config; + + /* Enable unit clock */ + clk_enable(keypad->clk); + + val = __raw_readl(keypad->mmio_base + KPI_CONF); + val |= (KPSEL | ENKP); + val &= ~(KSIZE0 | KSIZE1); + + config = pdata->prescale | (pdata->debounce << DEBOUNCE_BIT); + + val |= config; + + __raw_writel(val, keypad->mmio_base + KPI_CONF); + + return 0; +} + +static void w90p910_keypad_close(struct input_dev *dev) +{ + struct w90p910_keypad *keypad = input_get_drvdata(dev); + + /* Disable clock unit */ + clk_disable(keypad->clk); +} + +static int __devinit w90p910_keypad_probe(struct platform_device *pdev) +{ + const struct w90p910_keypad_platform_data *pdata = + pdev->dev.platform_data; + const struct matrix_keymap_data *keymap_data = pdata->keymap_data; + struct w90p910_keypad *keypad; + struct input_dev *input_dev; + struct resource *res; + int irq; + int error; + int i; + + if (!pdata) { + dev_err(&pdev->dev, "no platform data defined\n"); + return -EINVAL; + } + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(&pdev->dev, "failed to get keypad irq\n"); + return -ENXIO; + } + + keypad = kzalloc(sizeof(struct w90p910_keypad), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!keypad || !input_dev) { + dev_err(&pdev->dev, "failed to allocate driver data\n"); + error = -ENOMEM; + goto failed_free; + } + + keypad->pdata = pdata; + keypad->input_dev = input_dev; + keypad->irq = irq; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res == NULL) { + dev_err(&pdev->dev, "failed to get I/O memory\n"); + error = -ENXIO; + goto failed_free; + } + + res = request_mem_region(res->start, resource_size(res), pdev->name); + if (res == NULL) { + dev_err(&pdev->dev, "failed to request I/O memory\n"); + error = -EBUSY; + goto failed_free; + } + + keypad->mmio_base = ioremap(res->start, resource_size(res)); + if (keypad->mmio_base == NULL) { + dev_err(&pdev->dev, "failed to remap I/O memory\n"); + error = -ENXIO; + goto failed_free_res; + } + + keypad->clk = clk_get(&pdev->dev, NULL); + if (IS_ERR(keypad->clk)) { + dev_err(&pdev->dev, "failed to get keypad clock\n"); + error = PTR_ERR(keypad->clk); + goto failed_free_io; + } + + /* set multi-function pin for w90p910 kpi. */ + mfp_set_groupi(&pdev->dev); + + input_dev->name = pdev->name; + input_dev->id.bustype = BUS_HOST; + input_dev->open = w90p910_keypad_open; + input_dev->close = w90p910_keypad_close; + input_dev->dev.parent = &pdev->dev; + + input_dev->keycode = keypad->keymap; + input_dev->keycodesize = sizeof(keypad->keymap[0]); + input_dev->keycodemax = ARRAY_SIZE(keypad->keymap); + + input_set_drvdata(input_dev, keypad); + + input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP); + input_set_capability(input_dev, EV_MSC, MSC_SCAN); + + for (i = 0; i < keymap_data->keymap_size; i++) { + unsigned int key = keymap_data->keymap[i]; + unsigned int row = KEY_ROW(key); + unsigned int col = KEY_COL(key); + unsigned short keycode = KEY_VAL(key); + unsigned int scancode = MATRIX_SCAN_CODE(row, col, + W90P910_ROW_SHIFT); + + keypad->keymap[scancode] = keycode; + __set_bit(keycode, input_dev->keybit); + } + __clear_bit(KEY_RESERVED, input_dev->keybit); + + + error = request_irq(keypad->irq, w90p910_keypad_irq_handler, + IRQF_DISABLED, pdev->name, keypad); + if (error) { + dev_err(&pdev->dev, "failed to request IRQ\n"); + goto failed_put_clk; + } + + /* Register the input device */ + error = input_register_device(input_dev); + if (error) { + dev_err(&pdev->dev, "failed to register input device\n"); + goto failed_free_irq; + } + + platform_set_drvdata(pdev, keypad); + return 0; + +failed_free_irq: + free_irq(irq, pdev); +failed_put_clk: + clk_put(keypad->clk); +failed_free_io: + iounmap(keypad->mmio_base); +failed_free_res: + release_mem_region(res->start, resource_size(res)); +failed_free: + input_free_device(input_dev); + kfree(keypad); + return error; +} + +static int __devexit w90p910_keypad_remove(struct platform_device *pdev) +{ + struct w90p910_keypad *keypad = platform_get_drvdata(pdev); + struct resource *res; + + free_irq(keypad->irq, pdev); + + clk_put(keypad->clk); + + input_unregister_device(keypad->input_dev); + + iounmap(keypad->mmio_base); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + release_mem_region(res->start, resource_size(res)); + + platform_set_drvdata(pdev, NULL); + kfree(keypad); + + return 0; +} + +static struct platform_driver w90p910_keypad_driver = { + .probe = w90p910_keypad_probe, + .remove = __devexit_p(w90p910_keypad_remove), + .driver = { + .name = "nuc900-keypad", + .owner = THIS_MODULE, + }, +}; + +static int __init w90p910_keypad_init(void) +{ + return platform_driver_register(&w90p910_keypad_driver); +} + +static void __exit w90p910_keypad_exit(void) +{ + platform_driver_unregister(&w90p910_keypad_driver); +} + +module_init(w90p910_keypad_init); +module_exit(w90p910_keypad_exit); + +MODULE_AUTHOR("Wan ZongShun <mcuos.com@gmail.com>"); +MODULE_DESCRIPTION("w90p910 keypad driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:nuc900-keypad"); diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index 1acfa3a05aa..cbe21bc96b5 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -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 diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index 0d979fd4cd5..79c1e9a5ea3 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_INPUT_APANEL) += apanel.o obj-$(CONFIG_INPUT_ATI_REMOTE) += ati_remote.o obj-$(CONFIG_INPUT_ATI_REMOTE2) += ati_remote2.o obj-$(CONFIG_INPUT_ATLAS_BTNS) += atlas_btns.o +obj-$(CONFIG_INPUT_BFIN_ROTARY) += bfin_rotary.o obj-$(CONFIG_INPUT_CM109) += cm109.o obj-$(CONFIG_INPUT_COBALT_BTNS) += cobalt_btns.o obj-$(CONFIG_INPUT_DM355EVM) += dm355evm_keys.o diff --git a/drivers/input/misc/bfin_rotary.c b/drivers/input/misc/bfin_rotary.c new file mode 100644 index 00000000000..690f3fafa03 --- /dev/null +++ b/drivers/input/misc/bfin_rotary.c @@ -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"); diff --git a/drivers/input/misc/cobalt_btns.c b/drivers/input/misc/cobalt_btns.c index d114d3a9e1e..ee73d7219c9 100644 --- a/drivers/input/misc/cobalt_btns.c +++ b/drivers/input/misc/cobalt_btns.c @@ -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); diff --git a/drivers/input/misc/dm355evm_keys.c b/drivers/input/misc/dm355evm_keys.c index a63315ce4a6..0918acae584 100644 --- a/drivers/input/misc/dm355evm_keys.c +++ b/drivers/input/misc/dm355evm_keys.c @@ -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; diff --git a/drivers/input/misc/wistron_btns.c b/drivers/input/misc/wistron_btns.c index 27ee976eb54..ebb08cfe273 100644 --- a/drivers/input/misc/wistron_btns.c +++ b/drivers/input/misc/wistron_btns.c @@ -243,9 +243,9 @@ enum { KE_END, KE_KEY, KE_SW, KE_WIFI, KE_BLUETOOTH }; #define FE_UNTESTED 0x80 static struct key_entry *keymap; /* = NULL; Current key map */ -static int have_wifi; -static int have_bluetooth; -static int have_leds; +static bool have_wifi; +static bool have_bluetooth; +static int leds_present; /* bitmask of leds present */ static int __init dmi_matched(const struct dmi_system_id *dmi) { @@ -254,11 +254,11 @@ static int __init dmi_matched(const struct dmi_system_id *dmi) keymap = dmi->driver_data; for (key = keymap; key->type != KE_END; key++) { if (key->type == KE_WIFI) - have_wifi = 1; + have_wifi = true; else if (key->type == KE_BLUETOOTH) - have_bluetooth = 1; + have_bluetooth = true; } - have_leds = key->code & (FE_MAIL_LED | FE_WIFI_LED); + leds_present = key->code & (FE_MAIL_LED | FE_WIFI_LED); return 1; } @@ -1009,8 +1009,8 @@ static int __init select_keymap(void) static struct input_polled_dev *wistron_idev; static unsigned long jiffies_last_press; -static int wifi_enabled; -static int bluetooth_enabled; +static bool wifi_enabled; +static bool bluetooth_enabled; static void report_key(struct input_dev *dev, unsigned int keycode) { @@ -1053,24 +1053,24 @@ static struct led_classdev wistron_wifi_led = { static void __devinit wistron_led_init(struct device *parent) { - if (have_leds & FE_WIFI_LED) { + if (leds_present & FE_WIFI_LED) { u16 wifi = bios_get_default_setting(WIFI); if (wifi & 1) { wistron_wifi_led.brightness = (wifi & 2) ? LED_FULL : LED_OFF; if (led_classdev_register(parent, &wistron_wifi_led)) - have_leds &= ~FE_WIFI_LED; + leds_present &= ~FE_WIFI_LED; else bios_set_state(WIFI, wistron_wifi_led.brightness); } else - have_leds &= ~FE_WIFI_LED; + leds_present &= ~FE_WIFI_LED; } - if (have_leds & FE_MAIL_LED) { + if (leds_present & FE_MAIL_LED) { /* bios_get_default_setting(MAIL) always retuns 0, so just turn the led off */ wistron_mail_led.brightness = LED_OFF; if (led_classdev_register(parent, &wistron_mail_led)) - have_leds &= ~FE_MAIL_LED; + leds_present &= ~FE_MAIL_LED; else bios_set_state(MAIL_LED, wistron_mail_led.brightness); } @@ -1078,28 +1078,28 @@ static void __devinit wistron_led_init(struct device *parent) static void __devexit wistron_led_remove(void) { - if (have_leds & FE_MAIL_LED) + if (leds_present & FE_MAIL_LED) led_classdev_unregister(&wistron_mail_led); - if (have_leds & FE_WIFI_LED) + if (leds_present & FE_WIFI_LED) led_classdev_unregister(&wistron_wifi_led); } static inline void wistron_led_suspend(void) { - if (have_leds & FE_MAIL_LED) + if (leds_present & FE_MAIL_LED) led_classdev_suspend(&wistron_mail_led); - if (have_leds & FE_WIFI_LED) + if (leds_present & FE_WIFI_LED) led_classdev_suspend(&wistron_wifi_led); } static inline void wistron_led_resume(void) { - if (have_leds & FE_MAIL_LED) + if (leds_present & FE_MAIL_LED) led_classdev_resume(&wistron_mail_led); - if (have_leds & FE_WIFI_LED) + if (leds_present & FE_WIFI_LED) led_classdev_resume(&wistron_wifi_led); } @@ -1312,7 +1312,7 @@ static int __devinit wistron_probe(struct platform_device *dev) if (have_wifi) { u16 wifi = bios_get_default_setting(WIFI); if (wifi & 1) - wifi_enabled = (wifi & 2) ? 1 : 0; + wifi_enabled = wifi & 2; else have_wifi = 0; @@ -1323,15 +1323,16 @@ static int __devinit wistron_probe(struct platform_device *dev) if (have_bluetooth) { u16 bt = bios_get_default_setting(BLUETOOTH); if (bt & 1) - bluetooth_enabled = (bt & 2) ? 1 : 0; + bluetooth_enabled = bt & 2; else - have_bluetooth = 0; + have_bluetooth = false; if (have_bluetooth) bios_set_state(BLUETOOTH, bluetooth_enabled); } wistron_led_init(&dev->dev); + err = setup_input_dev(); if (err) { bios_detach(); @@ -1352,7 +1353,7 @@ static int __devexit wistron_remove(struct platform_device *dev) } #ifdef CONFIG_PM -static int wistron_suspend(struct platform_device *dev, pm_message_t state) +static int wistron_suspend(struct device *dev) { if (have_wifi) bios_set_state(WIFI, 0); @@ -1361,10 +1362,11 @@ static int wistron_suspend(struct platform_device *dev, pm_message_t state) bios_set_state(BLUETOOTH, 0); wistron_led_suspend(); + return 0; } -static int wistron_resume(struct platform_device *dev) +static int wistron_resume(struct device *dev) { if (have_wifi) bios_set_state(WIFI, wifi_enabled); @@ -1373,24 +1375,30 @@ static int wistron_resume(struct platform_device *dev) bios_set_state(BLUETOOTH, bluetooth_enabled); wistron_led_resume(); + poll_bios(true); return 0; } -#else -#define wistron_suspend NULL -#define wistron_resume NULL + +static const struct dev_pm_ops wistron_pm_ops = { + .suspend = wistron_suspend, + .resume = wistron_resume, + .poweroff = wistron_suspend, + .restore = wistron_resume, +}; #endif static struct platform_driver wistron_driver = { .driver = { .name = "wistron-bios", .owner = THIS_MODULE, +#if CONFIG_PM + .pm = &wistron_pm_ops, +#endif }, .probe = wistron_probe, .remove = __devexit_p(wistron_remove), - .suspend = wistron_suspend, - .resume = wistron_resume, }; static int __init wb_module_init(void) diff --git a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig index 8a2c5b14c8d..3feeb3af8ab 100644 --- a/drivers/input/mouse/Kconfig +++ b/drivers/input/mouse/Kconfig @@ -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 diff --git a/drivers/input/mouse/Makefile b/drivers/input/mouse/Makefile index 010f265ec15..570c84a4a65 100644 --- a/drivers/input/mouse/Makefile +++ b/drivers/input/mouse/Makefile @@ -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 diff --git a/drivers/input/mouse/hgpk.c b/drivers/input/mouse/hgpk.c index a1ad2f1a7bb..f5aa035774d 100644 --- a/drivers/input/mouse/hgpk.c +++ b/drivers/input/mouse/hgpk.c @@ -369,12 +369,46 @@ static ssize_t hgpk_set_powered(struct psmouse *psmouse, void *data, __PSMOUSE_DEFINE_ATTR(powered, S_IWUSR | S_IRUGO, NULL, hgpk_show_powered, hgpk_set_powered, 0); +static ssize_t hgpk_trigger_recal_show(struct psmouse *psmouse, + void *data, char *buf) +{ + return -EINVAL; +} + +static ssize_t hgpk_trigger_recal(struct psmouse *psmouse, void *data, + const char *buf, size_t count) +{ + struct hgpk_data *priv = psmouse->private; + unsigned long value; + int err; + + err = strict_strtoul(buf, 10, &value); + if (err || value != 1) + return -EINVAL; + + /* + * We queue work instead of doing recalibration right here + * to avoid adding locking to to hgpk_force_recalibrate() + * since workqueue provides serialization. + */ + psmouse_queue_work(psmouse, &priv->recalib_wq, 0); + return count; +} + +__PSMOUSE_DEFINE_ATTR(recalibrate, S_IWUSR | S_IRUGO, NULL, + hgpk_trigger_recal_show, hgpk_trigger_recal, 0); + static void hgpk_disconnect(struct psmouse *psmouse) { struct hgpk_data *priv = psmouse->private; device_remove_file(&psmouse->ps2dev.serio->dev, &psmouse_attr_powered.dattr); + + if (psmouse->model >= HGPK_MODEL_C) + device_remove_file(&psmouse->ps2dev.serio->dev, + &psmouse_attr_recalibrate.dattr); + psmouse_reset(psmouse); kfree(priv); } @@ -423,10 +457,25 @@ static int hgpk_register(struct psmouse *psmouse) err = device_create_file(&psmouse->ps2dev.serio->dev, &psmouse_attr_powered.dattr); - if (err) - hgpk_err(psmouse, "Failed to create sysfs attribute\n"); + if (err) { + hgpk_err(psmouse, "Failed creating 'powered' sysfs node\n"); + return err; + } - return err; + /* C-series touchpads added the recalibrate command */ + if (psmouse->model >= HGPK_MODEL_C) { + err = device_create_file(&psmouse->ps2dev.serio->dev, + &psmouse_attr_recalibrate.dattr); + if (err) { + hgpk_err(psmouse, + "Failed creating 'recalibrate' sysfs node\n"); + device_remove_file(&psmouse->ps2dev.serio->dev, + &psmouse_attr_powered.dattr); + return err; + } + } + + return 0; } int hgpk_init(struct psmouse *psmouse) diff --git a/drivers/input/mouse/hil_ptr.c b/drivers/input/mouse/hil_ptr.c deleted file mode 100644 index 3263ce083bf..00000000000 --- a/drivers/input/mouse/hil_ptr.c +++ /dev/null @@ -1,447 +0,0 @@ -/* - * Generic linux-input device driver for axis-bearing devices - * - * Copyright (c) 2001 Brian S. Julin - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL"). - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * - * References: - * HP-HIL Technical Reference Manual. Hewlett Packard Product No. 45918A - * - */ - -#include <linux/hil.h> -#include <linux/input.h> -#include <linux/serio.h> -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/init.h> -#include <linux/slab.h> -#include <linux/pci_ids.h> - -#define PREFIX "HIL PTR: " -#define HIL_GENERIC_NAME "HIL pointer device" - -MODULE_AUTHOR("Brian S. Julin <bri@calyx.com>"); -MODULE_DESCRIPTION(HIL_GENERIC_NAME " driver"); -MODULE_LICENSE("Dual BSD/GPL"); -MODULE_ALIAS("serio:ty03pr25id0Fex*"); - -#define TABLET_SIMULATES_MOUSE /* allow tablet to be used as mouse */ -#undef TABLET_AUTOADJUST /* auto-adjust valid tablet ranges */ - - -#define HIL_PTR_MAX_LENGTH 16 - -struct hil_ptr { - struct input_dev *dev; - struct serio *serio; - - /* Input buffer and index for packets from HIL bus. */ - hil_packet data[HIL_PTR_MAX_LENGTH]; - int idx4; /* four counts per packet */ - - /* Raw device info records from HIL bus, see hil.h for fields. */ - char idd[HIL_PTR_MAX_LENGTH]; /* DID byte and IDD record */ - char rsc[HIL_PTR_MAX_LENGTH]; /* RSC record */ - char exd[HIL_PTR_MAX_LENGTH]; /* EXD record */ - char rnm[HIL_PTR_MAX_LENGTH + 1]; /* RNM record + NULL term. */ - - /* Extra device details not contained in struct input_dev. */ - unsigned int nbtn, naxes; - unsigned int btnmap[7]; - - /* Something to sleep around with. */ - struct semaphore sem; -}; - -/* Process a complete packet after transfer from the HIL */ -static void hil_ptr_process_record(struct hil_ptr *ptr) -{ - struct input_dev *dev = ptr->dev; - hil_packet *data = ptr->data; - hil_packet p; - int idx, i, cnt, laxis; - int ax16, absdev; - - idx = ptr->idx4/4; - p = data[idx - 1]; - - if ((p & ~HIL_CMDCT_POL) == - (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_POL)) - goto report; - if ((p & ~HIL_CMDCT_RPL) == - (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_RPL)) - goto report; - - /* Not a poll response. See if we are loading config records. */ - switch (p & HIL_PKT_DATA_MASK) { - case HIL_CMD_IDD: - for (i = 0; i < idx; i++) - ptr->idd[i] = ptr->data[i] & HIL_PKT_DATA_MASK; - for (; i < HIL_PTR_MAX_LENGTH; i++) - ptr->idd[i] = 0; - break; - - case HIL_CMD_RSC: - for (i = 0; i < idx; i++) - ptr->rsc[i] = ptr->data[i] & HIL_PKT_DATA_MASK; - for (; i < HIL_PTR_MAX_LENGTH; i++) - ptr->rsc[i] = 0; - break; - - case HIL_CMD_EXD: - for (i = 0; i < idx; i++) - ptr->exd[i] = ptr->data[i] & HIL_PKT_DATA_MASK; - for (; i < HIL_PTR_MAX_LENGTH; i++) - ptr->exd[i] = 0; - break; - - case HIL_CMD_RNM: - for (i = 0; i < idx; i++) - ptr->rnm[i] = ptr->data[i] & HIL_PKT_DATA_MASK; - for (; i < HIL_PTR_MAX_LENGTH + 1; i++) - ptr->rnm[i] = 0; - break; - - default: - /* These occur when device isn't present */ - if (p == (HIL_ERR_INT | HIL_PKT_CMD)) - break; - /* Anything else we'd like to know about. */ - printk(KERN_WARNING PREFIX "Device sent unknown record %x\n", p); - break; - } - goto out; - - report: - if ((p & HIL_CMDCT_POL) != idx - 1) { - printk(KERN_WARNING PREFIX - "Malformed poll packet %x (idx = %i)\n", p, idx); - goto out; - } - - i = (ptr->data[0] & HIL_POL_AXIS_ALT) ? 3 : 0; - laxis = ptr->data[0] & HIL_POL_NUM_AXES_MASK; - laxis += i; - - ax16 = ptr->idd[1] & HIL_IDD_HEADER_16BIT; /* 8 or 16bit resolution */ - absdev = ptr->idd[1] & HIL_IDD_HEADER_ABS; - - for (cnt = 1; i < laxis; i++) { - unsigned int lo,hi,val; - lo = ptr->data[cnt++] & HIL_PKT_DATA_MASK; - hi = ax16 ? (ptr->data[cnt++] & HIL_PKT_DATA_MASK) : 0; - if (absdev) { - val = lo + (hi<<8); -#ifdef TABLET_AUTOADJUST - if (val < dev->absmin[ABS_X + i]) - dev->absmin[ABS_X + i] = val; - if (val > dev->absmax[ABS_X + i]) - dev->absmax[ABS_X + i] = val; -#endif - if (i%3) val = dev->absmax[ABS_X + i] - val; - input_report_abs(dev, ABS_X + i, val); - } else { - val = (int) (((int8_t)lo) | ((int8_t)hi<<8)); - if (i%3) - val *= -1; - input_report_rel(dev, REL_X + i, val); - } - } - - while (cnt < idx - 1) { - unsigned int btn; - int up; - btn = ptr->data[cnt++]; - up = btn & 1; - btn &= 0xfe; - if (btn == 0x8e) - continue; /* TODO: proximity == touch? */ - else - if ((btn > 0x8c) || (btn < 0x80)) - continue; - btn = (btn - 0x80) >> 1; - btn = ptr->btnmap[btn]; - input_report_key(dev, btn, !up); - } - input_sync(dev); - out: - ptr->idx4 = 0; - up(&ptr->sem); -} - -static void hil_ptr_process_err(struct hil_ptr *ptr) -{ - printk(KERN_WARNING PREFIX "errored HIL packet\n"); - ptr->idx4 = 0; - up(&ptr->sem); -} - -static irqreturn_t hil_ptr_interrupt(struct serio *serio, - unsigned char data, unsigned int flags) -{ - struct hil_ptr *ptr; - hil_packet packet; - int idx; - - ptr = serio_get_drvdata(serio); - BUG_ON(ptr == NULL); - - if (ptr->idx4 >= (HIL_PTR_MAX_LENGTH * sizeof(hil_packet))) { - hil_ptr_process_err(ptr); - return IRQ_HANDLED; - } - idx = ptr->idx4/4; - if (!(ptr->idx4 % 4)) - ptr->data[idx] = 0; - packet = ptr->data[idx]; - packet |= ((hil_packet)data) << ((3 - (ptr->idx4 % 4)) * 8); - ptr->data[idx] = packet; - - /* Records of N 4-byte hil_packets must terminate with a command. */ - if ((++(ptr->idx4)) % 4) - return IRQ_HANDLED; - if ((packet & 0xffff0000) != HIL_ERR_INT) { - hil_ptr_process_err(ptr); - return IRQ_HANDLED; - } - if (packet & HIL_PKT_CMD) - hil_ptr_process_record(ptr); - - return IRQ_HANDLED; -} - -static void hil_ptr_disconnect(struct serio *serio) -{ - struct hil_ptr *ptr; - - ptr = serio_get_drvdata(serio); - BUG_ON(ptr == NULL); - - serio_close(serio); - input_unregister_device(ptr->dev); - kfree(ptr); -} - -static int hil_ptr_connect(struct serio *serio, struct serio_driver *driver) -{ - struct hil_ptr *ptr; - const char *txt; - unsigned int i, naxsets, btntype; - uint8_t did, *idd; - int error; - - ptr = kzalloc(sizeof(struct hil_ptr), GFP_KERNEL); - if (!ptr) - return -ENOMEM; - - ptr->dev = input_allocate_device(); - if (!ptr->dev) { - error = -ENOMEM; - goto bail0; - } - - error = serio_open(serio, driver); - if (error) - goto bail1; - - serio_set_drvdata(serio, ptr); - ptr->serio = serio; - - init_MUTEX_LOCKED(&ptr->sem); - - /* Get device info. MLC driver supplies devid/status/etc. */ - serio->write(serio, 0); - serio->write(serio, 0); - serio->write(serio, HIL_PKT_CMD >> 8); - serio->write(serio, HIL_CMD_IDD); - down(&ptr->sem); - - serio->write(serio, 0); - serio->write(serio, 0); - serio->write(serio, HIL_PKT_CMD >> 8); - serio->write(serio, HIL_CMD_RSC); - down(&ptr->sem); - - serio->write(serio, 0); - serio->write(serio, 0); - serio->write(serio, HIL_PKT_CMD >> 8); - serio->write(serio, HIL_CMD_RNM); - down(&ptr->sem); - - serio->write(serio, 0); - serio->write(serio, 0); - serio->write(serio, HIL_PKT_CMD >> 8); - serio->write(serio, HIL_CMD_EXD); - down(&ptr->sem); - - up(&ptr->sem); - - did = ptr->idd[0]; - idd = ptr->idd + 1; - txt = "unknown"; - - if ((did & HIL_IDD_DID_TYPE_MASK) == HIL_IDD_DID_TYPE_REL) { - ptr->dev->evbit[0] = BIT_MASK(EV_REL); - txt = "relative"; - } - - if ((did & HIL_IDD_DID_TYPE_MASK) == HIL_IDD_DID_TYPE_ABS) { - ptr->dev->evbit[0] = BIT_MASK(EV_ABS); - txt = "absolute"; - } - - if (!ptr->dev->evbit[0]) { - error = -ENODEV; - goto bail2; - } - - ptr->nbtn = HIL_IDD_NUM_BUTTONS(idd); - if (ptr->nbtn) - ptr->dev->evbit[0] |= BIT_MASK(EV_KEY); - - naxsets = HIL_IDD_NUM_AXSETS(*idd); - ptr->naxes = HIL_IDD_NUM_AXES_PER_SET(*idd); - - printk(KERN_INFO PREFIX "HIL pointer device found (did: 0x%02x, axis: %s)\n", - did, txt); - printk(KERN_INFO PREFIX "HIL pointer has %i buttons and %i sets of %i axes\n", - ptr->nbtn, naxsets, ptr->naxes); - - btntype = BTN_MISC; - if ((did & HIL_IDD_DID_ABS_TABLET_MASK) == HIL_IDD_DID_ABS_TABLET) -#ifdef TABLET_SIMULATES_MOUSE - btntype = BTN_TOUCH; -#else - btntype = BTN_DIGI; -#endif - if ((did & HIL_IDD_DID_ABS_TSCREEN_MASK) == HIL_IDD_DID_ABS_TSCREEN) - btntype = BTN_TOUCH; - - if ((did & HIL_IDD_DID_REL_MOUSE_MASK) == HIL_IDD_DID_REL_MOUSE) - btntype = BTN_MOUSE; - - for (i = 0; i < ptr->nbtn; i++) { - set_bit(btntype | i, ptr->dev->keybit); - ptr->btnmap[i] = btntype | i; - } - - if (btntype == BTN_MOUSE) { - /* Swap buttons 2 and 3 */ - ptr->btnmap[1] = BTN_MIDDLE; - ptr->btnmap[2] = BTN_RIGHT; - } - - if ((did & HIL_IDD_DID_TYPE_MASK) == HIL_IDD_DID_TYPE_REL) { - for (i = 0; i < ptr->naxes; i++) - set_bit(REL_X + i, ptr->dev->relbit); - for (i = 3; (i < ptr->naxes + 3) && (naxsets > 1); i++) - set_bit(REL_X + i, ptr->dev->relbit); - } else { - for (i = 0; i < ptr->naxes; i++) { - set_bit(ABS_X + i, ptr->dev->absbit); - ptr->dev->absmin[ABS_X + i] = 0; - ptr->dev->absmax[ABS_X + i] = - HIL_IDD_AXIS_MAX((ptr->idd + 1), i); - } - for (i = 3; (i < ptr->naxes + 3) && (naxsets > 1); i++) { - set_bit(ABS_X + i, ptr->dev->absbit); - ptr->dev->absmin[ABS_X + i] = 0; - ptr->dev->absmax[ABS_X + i] = - HIL_IDD_AXIS_MAX((ptr->idd + 1), (i - 3)); - } -#ifdef TABLET_AUTOADJUST - for (i = 0; i < ABS_MAX; i++) { - int diff = ptr->dev->absmax[ABS_X + i] / 10; - ptr->dev->absmin[ABS_X + i] += diff; - ptr->dev->absmax[ABS_X + i] -= diff; - } -#endif - } - - ptr->dev->name = strlen(ptr->rnm) ? ptr->rnm : HIL_GENERIC_NAME; - - ptr->dev->id.bustype = BUS_HIL; - ptr->dev->id.vendor = PCI_VENDOR_ID_HP; - ptr->dev->id.product = 0x0001; /* TODO: get from ptr->rsc */ - ptr->dev->id.version = 0x0100; /* TODO: get from ptr->rsc */ - ptr->dev->dev.parent = &serio->dev; - - error = input_register_device(ptr->dev); - if (error) { - printk(KERN_INFO PREFIX "Unable to register input device\n"); - goto bail2; - } - - printk(KERN_INFO "input: %s (%s), ID: %d\n", - ptr->dev->name, - (btntype == BTN_MOUSE) ? "HIL mouse":"HIL tablet or touchpad", - did); - - return 0; - - bail2: - serio_close(serio); - bail1: - input_free_device(ptr->dev); - bail0: - kfree(ptr); - serio_set_drvdata(serio, NULL); - return error; -} - -static struct serio_device_id hil_ptr_ids[] = { - { - .type = SERIO_HIL_MLC, - .proto = SERIO_HIL, - .id = SERIO_ANY, - .extra = SERIO_ANY, - }, - { 0 } -}; - -static struct serio_driver hil_ptr_serio_driver = { - .driver = { - .name = "hil_ptr", - }, - .description = "HP HIL mouse/tablet driver", - .id_table = hil_ptr_ids, - .connect = hil_ptr_connect, - .disconnect = hil_ptr_disconnect, - .interrupt = hil_ptr_interrupt -}; - -static int __init hil_ptr_init(void) -{ - return serio_register_driver(&hil_ptr_serio_driver); -} - -static void __exit hil_ptr_exit(void) -{ - serio_unregister_driver(&hil_ptr_serio_driver); -} - -module_init(hil_ptr_init); -module_exit(hil_ptr_exit); diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c index b407b355dce..df318887ca0 100644 --- a/drivers/input/mouse/psmouse-base.c +++ b/drivers/input/mouse/psmouse-base.c @@ -30,6 +30,7 @@ #include "trackpoint.h" #include "touchkit_ps2.h" #include "elantech.h" +#include "sentelic.h" #define DRIVER_DESC "PS/2 mouse driver" @@ -666,6 +667,20 @@ static int psmouse_extensions(struct psmouse *psmouse, max_proto = PSMOUSE_IMEX; } +/* + * Try Finger Sensing Pad + */ + if (max_proto > PSMOUSE_IMEX) { + if (fsp_detect(psmouse, set_properties) == 0) { + if (!set_properties || fsp_init(psmouse) == 0) + return PSMOUSE_FSP; +/* + * Init failed, try basic relative protocols + */ + max_proto = PSMOUSE_IMEX; + } + } + if (max_proto > PSMOUSE_IMEX) { if (genius_detect(psmouse, set_properties) == 0) return PSMOUSE_GENPS; @@ -813,7 +828,16 @@ static const struct psmouse_protocol psmouse_protocols[] = { .detect = elantech_detect, .init = elantech_init, }, - #endif +#endif +#ifdef CONFIG_MOUSE_PS2_SENTELIC + { + .type = PSMOUSE_FSP, + .name = "FSPPS/2", + .alias = "fsp", + .detect = fsp_detect, + .init = fsp_init, + }, +#endif { .type = PSMOUSE_CORTRON, .name = "CortronPS/2", diff --git a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h index 54ed267894b..cca1744c2a0 100644 --- a/drivers/input/mouse/psmouse.h +++ b/drivers/input/mouse/psmouse.h @@ -91,6 +91,7 @@ enum psmouse_type { PSMOUSE_CORTRON, PSMOUSE_HGPK, PSMOUSE_ELANTECH, + PSMOUSE_FSP, PSMOUSE_AUTO /* This one should always be last */ }; @@ -116,9 +117,7 @@ ssize_t psmouse_attr_show_helper(struct device *dev, struct device_attribute *at ssize_t psmouse_attr_set_helper(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); -#define __PSMOUSE_DEFINE_ATTR(_name, _mode, _data, _show, _set, _protect) \ -static ssize_t _show(struct psmouse *, void *data, char *); \ -static ssize_t _set(struct psmouse *, void *data, const char *, size_t); \ +#define __PSMOUSE_DEFINE_ATTR_VAR(_name, _mode, _data, _show, _set, _protect) \ static struct psmouse_attribute psmouse_attr_##_name = { \ .dattr = { \ .attr = { \ @@ -134,7 +133,20 @@ static struct psmouse_attribute psmouse_attr_##_name = { \ .protect = _protect, \ } -#define PSMOUSE_DEFINE_ATTR(_name, _mode, _data, _show, _set) \ - __PSMOUSE_DEFINE_ATTR(_name, _mode, _data, _show, _set, 1) +#define __PSMOUSE_DEFINE_ATTR(_name, _mode, _data, _show, _set, _protect) \ + static ssize_t _show(struct psmouse *, void *, char *); \ + static ssize_t _set(struct psmouse *, void *, const char *, size_t); \ + __PSMOUSE_DEFINE_ATTR_VAR(_name, _mode, _data, _show, _set, _protect) + +#define PSMOUSE_DEFINE_ATTR(_name, _mode, _data, _show, _set) \ + __PSMOUSE_DEFINE_ATTR(_name, _mode, _data, _show, _set, 1) + +#define PSMOUSE_DEFINE_RO_ATTR(_name, _mode, _data, _show) \ + static ssize_t _show(struct psmouse *, void *, char *); \ + __PSMOUSE_DEFINE_ATTR_VAR(_name, _mode, _data, _show, NULL, 1) + +#define PSMOUSE_DEFINE_WO_ATTR(_name, _mode, _data, _set) \ + static ssize_t _set(struct psmouse *, void *, const char *, size_t); \ + __PSMOUSE_DEFINE_ATTR_VAR(_name, _mode, _data, NULL, _set, 1) #endif /* _PSMOUSE_H */ diff --git a/drivers/input/mouse/sentelic.c b/drivers/input/mouse/sentelic.c new file mode 100644 index 00000000000..97b1e72855a --- /dev/null +++ b/drivers/input/mouse/sentelic.c @@ -0,0 +1,867 @@ +/*- + * Finger Sensing Pad PS/2 mouse driver. + * + * Copyright (C) 2005-2007 Asia Vital Components Co., Ltd. + * Copyright (C) 2005-2009 Tai-hwa Liang, Sentelic Corporation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <linux/module.h> +#include <linux/version.h> +#include <linux/input.h> +#include <linux/ctype.h> +#include <linux/libps2.h> +#include <linux/serio.h> +#include <linux/jiffies.h> + +#include "psmouse.h" +#include "sentelic.h" + +/* + * Timeout for FSP PS/2 command only (in milliseconds). + */ +#define FSP_CMD_TIMEOUT 200 +#define FSP_CMD_TIMEOUT2 30 + +/** Driver version. */ +static const char fsp_drv_ver[] = "1.0.0-K"; + +/* + * Make sure that the value being sent to FSP will not conflict with + * possible sample rate values. + */ +static unsigned char fsp_test_swap_cmd(unsigned char reg_val) +{ + switch (reg_val) { + case 10: case 20: case 40: case 60: case 80: case 100: case 200: + /* + * The requested value being sent to FSP matched to possible + * sample rates, swap the given value such that the hardware + * wouldn't get confused. + */ + return (reg_val >> 4) | (reg_val << 4); + default: + return reg_val; /* swap isn't necessary */ + } +} + +/* + * Make sure that the value being sent to FSP will not conflict with certain + * commands. + */ +static unsigned char fsp_test_invert_cmd(unsigned char reg_val) +{ + switch (reg_val) { + case 0xe9: case 0xee: case 0xf2: case 0xff: + /* + * The requested value being sent to FSP matched to certain + * commands, inverse the given value such that the hardware + * wouldn't get confused. + */ + return ~reg_val; + default: + return reg_val; /* inversion isn't necessary */ + } +} + +static int fsp_reg_read(struct psmouse *psmouse, int reg_addr, int *reg_val) +{ + struct ps2dev *ps2dev = &psmouse->ps2dev; + unsigned char param[3]; + unsigned char addr; + int rc = -1; + + /* + * We need to shut off the device and switch it into command + * mode so we don't confuse our protocol handler. We don't need + * to do that for writes because sysfs set helper does this for + * us. + */ + ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE); + psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); + mutex_lock(&ps2dev->cmd_mutex); + + if (ps2_sendbyte(ps2dev, 0xf3, FSP_CMD_TIMEOUT) < 0) + goto out; + + /* should return 0xfe(request for resending) */ + ps2_sendbyte(ps2dev, 0x66, FSP_CMD_TIMEOUT2); + /* should return 0xfc(failed) */ + ps2_sendbyte(ps2dev, 0x88, FSP_CMD_TIMEOUT2); + + if (ps2_sendbyte(ps2dev, 0xf3, FSP_CMD_TIMEOUT) < 0) + goto out; + + if ((addr = fsp_test_invert_cmd(reg_addr)) != reg_addr) { + ps2_sendbyte(ps2dev, 0x68, FSP_CMD_TIMEOUT2); + } else if ((addr = fsp_test_swap_cmd(reg_addr)) != reg_addr) { + /* swapping is required */ + ps2_sendbyte(ps2dev, 0xcc, FSP_CMD_TIMEOUT2); + /* expect 0xfe */ + } else { + /* swapping isn't necessary */ + ps2_sendbyte(ps2dev, 0x66, FSP_CMD_TIMEOUT2); + /* expect 0xfe */ + } + /* should return 0xfc(failed) */ + ps2_sendbyte(ps2dev, addr, FSP_CMD_TIMEOUT); + + if (__ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO) < 0) + goto out; + + *reg_val = param[2]; + rc = 0; + + out: + mutex_unlock(&ps2dev->cmd_mutex); + ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE); + psmouse_set_state(psmouse, PSMOUSE_ACTIVATED); + dev_dbg(&ps2dev->serio->dev, "READ REG: 0x%02x is 0x%02x (rc = %d)\n", + reg_addr, *reg_val, rc); + return rc; +} + +static int fsp_reg_write(struct psmouse *psmouse, int reg_addr, int reg_val) +{ + struct ps2dev *ps2dev = &psmouse->ps2dev; + unsigned char v; + int rc = -1; + + mutex_lock(&ps2dev->cmd_mutex); + + if (ps2_sendbyte(ps2dev, 0xf3, FSP_CMD_TIMEOUT) < 0) + goto out; + + if ((v = fsp_test_invert_cmd(reg_addr)) != reg_addr) { + /* inversion is required */ + ps2_sendbyte(ps2dev, 0x74, FSP_CMD_TIMEOUT2); + } else { + if ((v = fsp_test_swap_cmd(reg_addr)) != reg_addr) { + /* swapping is required */ + ps2_sendbyte(ps2dev, 0x77, FSP_CMD_TIMEOUT2); + } else { + /* swapping isn't necessary */ + ps2_sendbyte(ps2dev, 0x55, FSP_CMD_TIMEOUT2); + } + } + /* write the register address in correct order */ + ps2_sendbyte(ps2dev, v, FSP_CMD_TIMEOUT2); + + if (ps2_sendbyte(ps2dev, 0xf3, FSP_CMD_TIMEOUT) < 0) + return -1; + + if ((v = fsp_test_invert_cmd(reg_val)) != reg_val) { + /* inversion is required */ + ps2_sendbyte(ps2dev, 0x47, FSP_CMD_TIMEOUT2); + } else if ((v = fsp_test_swap_cmd(reg_val)) != reg_val) { + /* swapping is required */ + ps2_sendbyte(ps2dev, 0x44, FSP_CMD_TIMEOUT2); + } else { + /* swapping isn't necessary */ + ps2_sendbyte(ps2dev, 0x33, FSP_CMD_TIMEOUT2); + } + + /* write the register value in correct order */ + ps2_sendbyte(ps2dev, v, FSP_CMD_TIMEOUT2); + rc = 0; + + out: + mutex_unlock(&ps2dev->cmd_mutex); + dev_dbg(&ps2dev->serio->dev, "WRITE REG: 0x%02x to 0x%02x (rc = %d)\n", + reg_addr, reg_val, rc); + return rc; +} + +/* Enable register clock gating for writing certain registers */ +static int fsp_reg_write_enable(struct psmouse *psmouse, bool enable) +{ + int v, nv; + + if (fsp_reg_read(psmouse, FSP_REG_SYSCTL1, &v) == -1) + return -1; + + if (enable) + nv = v | FSP_BIT_EN_REG_CLK; + else + nv = v & ~FSP_BIT_EN_REG_CLK; + + /* only write if necessary */ + if (nv != v) + if (fsp_reg_write(psmouse, FSP_REG_SYSCTL1, nv) == -1) + return -1; + + return 0; +} + +static int fsp_page_reg_read(struct psmouse *psmouse, int *reg_val) +{ + struct ps2dev *ps2dev = &psmouse->ps2dev; + unsigned char param[3]; + int rc = -1; + + ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE); + psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); + mutex_lock(&ps2dev->cmd_mutex); + + if (ps2_sendbyte(ps2dev, 0xf3, FSP_CMD_TIMEOUT) < 0) + goto out; + + ps2_sendbyte(ps2dev, 0x66, FSP_CMD_TIMEOUT2); + ps2_sendbyte(ps2dev, 0x88, FSP_CMD_TIMEOUT2); + + if (ps2_sendbyte(ps2dev, 0xf3, FSP_CMD_TIMEOUT) < 0) + goto out; + + ps2_sendbyte(ps2dev, 0x83, FSP_CMD_TIMEOUT2); + ps2_sendbyte(ps2dev, 0x88, FSP_CMD_TIMEOUT2); + + /* get the returned result */ + if (__ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO)) + goto out; + + *reg_val = param[2]; + rc = 0; + + out: + mutex_unlock(&ps2dev->cmd_mutex); + ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE); + psmouse_set_state(psmouse, PSMOUSE_ACTIVATED); + dev_dbg(&ps2dev->serio->dev, "READ PAGE REG: 0x%02x (rc = %d)\n", + *reg_val, rc); + return rc; +} + +static int fsp_page_reg_write(struct psmouse *psmouse, int reg_val) +{ + struct ps2dev *ps2dev = &psmouse->ps2dev; + unsigned char v; + int rc = -1; + + mutex_lock(&ps2dev->cmd_mutex); + + if (ps2_sendbyte(ps2dev, 0xf3, FSP_CMD_TIMEOUT) < 0) + goto out; + + ps2_sendbyte(ps2dev, 0x38, FSP_CMD_TIMEOUT2); + ps2_sendbyte(ps2dev, 0x88, FSP_CMD_TIMEOUT2); + + if (ps2_sendbyte(ps2dev, 0xf3, FSP_CMD_TIMEOUT) < 0) + return -1; + + if ((v = fsp_test_invert_cmd(reg_val)) != reg_val) { + ps2_sendbyte(ps2dev, 0x47, FSP_CMD_TIMEOUT2); + } else if ((v = fsp_test_swap_cmd(reg_val)) != reg_val) { + /* swapping is required */ + ps2_sendbyte(ps2dev, 0x44, FSP_CMD_TIMEOUT2); + } else { + /* swapping isn't necessary */ + ps2_sendbyte(ps2dev, 0x33, FSP_CMD_TIMEOUT2); + } + + ps2_sendbyte(ps2dev, v, FSP_CMD_TIMEOUT2); + rc = 0; + + out: + mutex_unlock(&ps2dev->cmd_mutex); + dev_dbg(&ps2dev->serio->dev, "WRITE PAGE REG: to 0x%02x (rc = %d)\n", + reg_val, rc); + return rc; +} + +static int fsp_get_version(struct psmouse *psmouse, int *version) +{ + if (fsp_reg_read(psmouse, FSP_REG_VERSION, version)) + return -EIO; + + return 0; +} + +static int fsp_get_revision(struct psmouse *psmouse, int *rev) +{ + if (fsp_reg_read(psmouse, FSP_REG_REVISION, rev)) + return -EIO; + + return 0; +} + +static int fsp_get_buttons(struct psmouse *psmouse, int *btn) +{ + static const int buttons[] = { + 0x16, /* Left/Middle/Right/Forward/Backward & Scroll Up/Down */ + 0x06, /* Left/Middle/Right & Scroll Up/Down/Right/Left */ + 0x04, /* Left/Middle/Right & Scroll Up/Down */ + 0x02, /* Left/Middle/Right */ + }; + int val; + + if (fsp_reg_read(psmouse, FSP_REG_TMOD_STATUS1, &val) == -1) + return -EIO; + + *btn = buttons[(val & 0x30) >> 4]; + return 0; +} + +/* Enable on-pad command tag output */ +static int fsp_opc_tag_enable(struct psmouse *psmouse, bool enable) +{ + int v, nv; + int res = 0; + + if (fsp_reg_read(psmouse, FSP_REG_OPC_QDOWN, &v) == -1) { + dev_err(&psmouse->ps2dev.serio->dev, "Unable get OPC state.\n"); + return -EIO; + } + + if (enable) + nv = v | FSP_BIT_EN_OPC_TAG; + else + nv = v & ~FSP_BIT_EN_OPC_TAG; + + /* only write if necessary */ + if (nv != v) { + fsp_reg_write_enable(psmouse, true); + res = fsp_reg_write(psmouse, FSP_REG_OPC_QDOWN, nv); + fsp_reg_write_enable(psmouse, false); + } + + if (res != 0) { + dev_err(&psmouse->ps2dev.serio->dev, + "Unable to enable OPC tag.\n"); + res = -EIO; + } + + return res; +} + +static int fsp_onpad_vscr(struct psmouse *psmouse, bool enable) +{ + struct fsp_data *pad = psmouse->private; + int val; + + if (fsp_reg_read(psmouse, FSP_REG_ONPAD_CTL, &val)) + return -EIO; + + pad->vscroll = enable; + + if (enable) + val |= (FSP_BIT_FIX_VSCR | FSP_BIT_ONPAD_ENABLE); + else + val &= ~FSP_BIT_FIX_VSCR; + + if (fsp_reg_write(psmouse, FSP_REG_ONPAD_CTL, val)) + return -EIO; + + return 0; +} + +static int fsp_onpad_hscr(struct psmouse *psmouse, bool enable) +{ + struct fsp_data *pad = psmouse->private; + int val, v2; + + if (fsp_reg_read(psmouse, FSP_REG_ONPAD_CTL, &val)) + return -EIO; + + if (fsp_reg_read(psmouse, FSP_REG_SYSCTL5, &v2)) + return -EIO; + + pad->hscroll = enable; + + if (enable) { + val |= (FSP_BIT_FIX_HSCR | FSP_BIT_ONPAD_ENABLE); + v2 |= FSP_BIT_EN_MSID6; + } else { + val &= ~FSP_BIT_FIX_HSCR; + v2 &= ~(FSP_BIT_EN_MSID6 | FSP_BIT_EN_MSID7 | FSP_BIT_EN_MSID8); + } + + if (fsp_reg_write(psmouse, FSP_REG_ONPAD_CTL, val)) + return -EIO; + + /* reconfigure horizontal scrolling packet output */ + if (fsp_reg_write(psmouse, FSP_REG_SYSCTL5, v2)) + return -EIO; + + return 0; +} + +/* + * Write device specific initial parameters. + * + * ex: 0xab 0xcd - write oxcd into register 0xab + */ +static ssize_t fsp_attr_set_setreg(struct psmouse *psmouse, void *data, + const char *buf, size_t count) +{ + unsigned long reg, val; + char *rest; + ssize_t retval; + + reg = simple_strtoul(buf, &rest, 16); + if (rest == buf || *rest != ' ' || reg > 0xff) + return -EINVAL; + + if (strict_strtoul(rest + 1, 16, &val) || val > 0xff) + return -EINVAL; + + if (fsp_reg_write_enable(psmouse, true)) + return -EIO; + + retval = fsp_reg_write(psmouse, reg, val) < 0 ? -EIO : count; + + fsp_reg_write_enable(psmouse, false); + + return count; +} + +PSMOUSE_DEFINE_WO_ATTR(setreg, S_IWUSR, NULL, fsp_attr_set_setreg); + +static ssize_t fsp_attr_show_getreg(struct psmouse *psmouse, + void *data, char *buf) +{ + struct fsp_data *pad = psmouse->private; + + return sprintf(buf, "%02x%02x\n", pad->last_reg, pad->last_val); +} + +/* + * Read a register from device. + * + * ex: 0xab -- read content from register 0xab + */ +static ssize_t fsp_attr_set_getreg(struct psmouse *psmouse, void *data, + const char *buf, size_t count) +{ + struct fsp_data *pad = psmouse->private; + unsigned long reg; + int val; + + if (strict_strtoul(buf, 16, ®) || reg > 0xff) + return -EINVAL; + + if (fsp_reg_read(psmouse, reg, &val)) + return -EIO; + + pad->last_reg = reg; + pad->last_val = val; + + return count; +} + +PSMOUSE_DEFINE_ATTR(getreg, S_IWUSR | S_IRUGO, NULL, + fsp_attr_show_getreg, fsp_attr_set_getreg); + +static ssize_t fsp_attr_show_pagereg(struct psmouse *psmouse, + void *data, char *buf) +{ + int val = 0; + + if (fsp_page_reg_read(psmouse, &val)) + return -EIO; + + return sprintf(buf, "%02x\n", val); +} + +static ssize_t fsp_attr_set_pagereg(struct psmouse *psmouse, void *data, + const char *buf, size_t count) +{ + unsigned long val; + + if (strict_strtoul(buf, 16, &val) || val > 0xff) + return -EINVAL; + + if (fsp_page_reg_write(psmouse, val)) + return -EIO; + + return count; +} + +PSMOUSE_DEFINE_ATTR(page, S_IWUSR | S_IRUGO, NULL, + fsp_attr_show_pagereg, fsp_attr_set_pagereg); + +static ssize_t fsp_attr_show_vscroll(struct psmouse *psmouse, + void *data, char *buf) +{ + struct fsp_data *pad = psmouse->private; + + return sprintf(buf, "%d\n", pad->vscroll); +} + +static ssize_t fsp_attr_set_vscroll(struct psmouse *psmouse, void *data, + const char *buf, size_t count) +{ + unsigned long val; + + if (strict_strtoul(buf, 10, &val) || val > 1) + return -EINVAL; + + fsp_onpad_vscr(psmouse, val); + + return count; +} + +PSMOUSE_DEFINE_ATTR(vscroll, S_IWUSR | S_IRUGO, NULL, + fsp_attr_show_vscroll, fsp_attr_set_vscroll); + +static ssize_t fsp_attr_show_hscroll(struct psmouse *psmouse, + void *data, char *buf) +{ + struct fsp_data *pad = psmouse->private; + + return sprintf(buf, "%d\n", pad->hscroll); +} + +static ssize_t fsp_attr_set_hscroll(struct psmouse *psmouse, void *data, + const char *buf, size_t count) +{ + unsigned long val; + + if (strict_strtoul(buf, 10, &val) || val > 1) + return -EINVAL; + + fsp_onpad_hscr(psmouse, val); + + return count; +} + +PSMOUSE_DEFINE_ATTR(hscroll, S_IWUSR | S_IRUGO, NULL, + fsp_attr_show_hscroll, fsp_attr_set_hscroll); + +static ssize_t fsp_attr_show_flags(struct psmouse *psmouse, + void *data, char *buf) +{ + struct fsp_data *pad = psmouse->private; + + return sprintf(buf, "%c\n", + pad->flags & FSPDRV_FLAG_EN_OPC ? 'C' : 'c'); +} + +static ssize_t fsp_attr_set_flags(struct psmouse *psmouse, void *data, + const char *buf, size_t count) +{ + struct fsp_data *pad = psmouse->private; + size_t i; + + for (i = 0; i < count; i++) { + switch (buf[i]) { + case 'C': + pad->flags |= FSPDRV_FLAG_EN_OPC; + break; + case 'c': + pad->flags &= ~FSPDRV_FLAG_EN_OPC; + break; + default: + return -EINVAL; + } + } + return count; +} + +PSMOUSE_DEFINE_ATTR(flags, S_IWUSR | S_IRUGO, NULL, + fsp_attr_show_flags, fsp_attr_set_flags); + +static ssize_t fsp_attr_show_ver(struct psmouse *psmouse, + void *data, char *buf) +{ + return sprintf(buf, "Sentelic FSP kernel module %s\n", fsp_drv_ver); +} + +PSMOUSE_DEFINE_RO_ATTR(ver, S_IRUGO, NULL, fsp_attr_show_ver); + +static struct attribute *fsp_attributes[] = { + &psmouse_attr_setreg.dattr.attr, + &psmouse_attr_getreg.dattr.attr, + &psmouse_attr_page.dattr.attr, + &psmouse_attr_vscroll.dattr.attr, + &psmouse_attr_hscroll.dattr.attr, + &psmouse_attr_flags.dattr.attr, + &psmouse_attr_ver.dattr.attr, + NULL +}; + +static struct attribute_group fsp_attribute_group = { + .attrs = fsp_attributes, +}; + +#ifdef FSP_DEBUG +static void fsp_packet_debug(unsigned char packet[]) +{ + static unsigned int ps2_packet_cnt; + static unsigned int ps2_last_second; + unsigned int jiffies_msec; + + ps2_packet_cnt++; + jiffies_msec = jiffies_to_msecs(jiffies); + printk(KERN_DEBUG "%08dms PS/2 packets: %02x, %02x, %02x, %02x\n", + jiffies_msec, packet[0], packet[1], packet[2], packet[3]); + + if (jiffies_msec - ps2_last_second > 1000) { + printk(KERN_DEBUG "PS/2 packets/sec = %d\n", ps2_packet_cnt); + ps2_packet_cnt = 0; + ps2_last_second = jiffies_msec; + } +} +#else +static void fsp_packet_debug(unsigned char packet[]) +{ +} +#endif + +static psmouse_ret_t fsp_process_byte(struct psmouse *psmouse) +{ + struct input_dev *dev = psmouse->dev; + struct fsp_data *ad = psmouse->private; + unsigned char *packet = psmouse->packet; + unsigned char button_status = 0, lscroll = 0, rscroll = 0; + int rel_x, rel_y; + + if (psmouse->pktcnt < 4) + return PSMOUSE_GOOD_DATA; + + /* + * Full packet accumulated, process it + */ + + switch (psmouse->packet[0] >> FSP_PKT_TYPE_SHIFT) { + case FSP_PKT_TYPE_ABS: + dev_warn(&psmouse->ps2dev.serio->dev, + "Unexpected absolute mode packet, ignored.\n"); + break; + + case FSP_PKT_TYPE_NORMAL_OPC: + /* on-pad click, filter it if necessary */ + if ((ad->flags & FSPDRV_FLAG_EN_OPC) != FSPDRV_FLAG_EN_OPC) + packet[0] &= ~BIT(0); + /* fall through */ + + case FSP_PKT_TYPE_NORMAL: + /* normal packet */ + /* special packet data translation from on-pad packets */ + if (packet[3] != 0) { + if (packet[3] & BIT(0)) + button_status |= 0x01; /* wheel down */ + if (packet[3] & BIT(1)) + button_status |= 0x0f; /* wheel up */ + if (packet[3] & BIT(2)) + button_status |= BIT(5);/* horizontal left */ + if (packet[3] & BIT(3)) + button_status |= BIT(4);/* horizontal right */ + /* push back to packet queue */ + if (button_status != 0) + packet[3] = button_status; + rscroll = (packet[3] >> 4) & 1; + lscroll = (packet[3] >> 5) & 1; + } + /* + * Processing wheel up/down and extra button events + */ + input_report_rel(dev, REL_WHEEL, + (int)(packet[3] & 8) - (int)(packet[3] & 7)); + input_report_rel(dev, REL_HWHEEL, lscroll - rscroll); + input_report_key(dev, BTN_BACK, lscroll); + input_report_key(dev, BTN_FORWARD, rscroll); + + /* + * Standard PS/2 Mouse + */ + input_report_key(dev, BTN_LEFT, packet[0] & 1); + input_report_key(dev, BTN_MIDDLE, (packet[0] >> 2) & 1); + input_report_key(dev, BTN_RIGHT, (packet[0] >> 1) & 1); + + rel_x = packet[1] ? (int)packet[1] - (int)((packet[0] << 4) & 0x100) : 0; + rel_y = packet[2] ? (int)((packet[0] << 3) & 0x100) - (int)packet[2] : 0; + + input_report_rel(dev, REL_X, rel_x); + input_report_rel(dev, REL_Y, rel_y); + break; + } + + input_sync(dev); + + fsp_packet_debug(packet); + + return PSMOUSE_FULL_PACKET; +} + +static int fsp_activate_protocol(struct psmouse *psmouse) +{ + struct fsp_data *pad = psmouse->private; + struct ps2dev *ps2dev = &psmouse->ps2dev; + unsigned char param[2]; + int val; + + /* + * Standard procedure to enter FSP Intellimouse mode + * (scrolling wheel, 4th and 5th buttons) + */ + param[0] = 200; + ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE); + param[0] = 200; + ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE); + param[0] = 80; + ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE); + + ps2_command(ps2dev, param, PSMOUSE_CMD_GETID); + if (param[0] != 0x04) { + dev_err(&psmouse->ps2dev.serio->dev, + "Unable to enable 4 bytes packet format.\n"); + return -EIO; + } + + if (fsp_reg_read(psmouse, FSP_REG_SYSCTL5, &val)) { + dev_err(&psmouse->ps2dev.serio->dev, + "Unable to read SYSCTL5 register.\n"); + return -EIO; + } + + val &= ~(FSP_BIT_EN_MSID7 | FSP_BIT_EN_MSID8 | FSP_BIT_EN_AUTO_MSID8); + /* Ensure we are not in absolute mode */ + val &= ~FSP_BIT_EN_PKT_G0; + if (pad->buttons == 0x06) { + /* Left/Middle/Right & Scroll Up/Down/Right/Left */ + val |= FSP_BIT_EN_MSID6; + } + + if (fsp_reg_write(psmouse, FSP_REG_SYSCTL5, val)) { + dev_err(&psmouse->ps2dev.serio->dev, + "Unable to set up required mode bits.\n"); + return -EIO; + } + + /* + * Enable OPC tags such that driver can tell the difference between + * on-pad and real button click + */ + if (fsp_opc_tag_enable(psmouse, true)) + dev_warn(&psmouse->ps2dev.serio->dev, + "Failed to enable OPC tag mode.\n"); + + /* Enable on-pad vertical and horizontal scrolling */ + fsp_onpad_vscr(psmouse, true); + fsp_onpad_hscr(psmouse, true); + + return 0; +} + +int fsp_detect(struct psmouse *psmouse, int set_properties) +{ + int id; + + if (fsp_reg_read(psmouse, FSP_REG_DEVICE_ID, &id)) + return -EIO; + + if (id != 0x01) + return -ENODEV; + + if (set_properties) { + psmouse->vendor = "Sentelic"; + psmouse->name = "FingerSensingPad"; + } + + return 0; +} + +static void fsp_reset(struct psmouse *psmouse) +{ + fsp_opc_tag_enable(psmouse, false); + fsp_onpad_vscr(psmouse, false); + fsp_onpad_hscr(psmouse, false); +} + +static void fsp_disconnect(struct psmouse *psmouse) +{ + sysfs_remove_group(&psmouse->ps2dev.serio->dev.kobj, + &fsp_attribute_group); + + fsp_reset(psmouse); + kfree(psmouse->private); +} + +static int fsp_reconnect(struct psmouse *psmouse) +{ + int version; + + if (fsp_detect(psmouse, 0)) + return -ENODEV; + + if (fsp_get_version(psmouse, &version)) + return -ENODEV; + + if (fsp_activate_protocol(psmouse)) + return -EIO; + + return 0; +} + +int fsp_init(struct psmouse *psmouse) +{ + struct fsp_data *priv; + int ver, rev, buttons; + int error; + + if (fsp_get_version(psmouse, &ver) || + fsp_get_revision(psmouse, &rev) || + fsp_get_buttons(psmouse, &buttons)) { + return -ENODEV; + } + + printk(KERN_INFO + "Finger Sensing Pad, hw: %d.%d.%d, sw: %s, buttons: %d\n", + ver >> 4, ver & 0x0F, rev, fsp_drv_ver, buttons & 7); + + psmouse->private = priv = kzalloc(sizeof(struct fsp_data), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->ver = ver; + priv->rev = rev; + priv->buttons = buttons; + + /* enable on-pad click by default */ + priv->flags |= FSPDRV_FLAG_EN_OPC; + + /* Set up various supported input event bits */ + __set_bit(BTN_BACK, psmouse->dev->keybit); + __set_bit(BTN_FORWARD, psmouse->dev->keybit); + __set_bit(REL_WHEEL, psmouse->dev->relbit); + __set_bit(REL_HWHEEL, psmouse->dev->relbit); + + psmouse->protocol_handler = fsp_process_byte; + psmouse->disconnect = fsp_disconnect; + psmouse->reconnect = fsp_reconnect; + psmouse->cleanup = fsp_reset; + psmouse->pktsize = 4; + + /* set default packet output based on number of buttons we found */ + error = fsp_activate_protocol(psmouse); + if (error) + goto err_out; + + error = sysfs_create_group(&psmouse->ps2dev.serio->dev.kobj, + &fsp_attribute_group); + if (error) { + dev_err(&psmouse->ps2dev.serio->dev, + "Failed to create sysfs attributes (%d)", error); + goto err_out; + } + + return 0; + + err_out: + kfree(psmouse->private); + psmouse->private = NULL; + return error; +} diff --git a/drivers/input/mouse/sentelic.h b/drivers/input/mouse/sentelic.h new file mode 100644 index 00000000000..083559c7282 --- /dev/null +++ b/drivers/input/mouse/sentelic.h @@ -0,0 +1,98 @@ +/*- + * Finger Sensing Pad PS/2 mouse driver. + * + * Copyright (C) 2005-2007 Asia Vital Components Co., Ltd. + * Copyright (C) 2005-2009 Tai-hwa Liang, Sentelic Corporation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef __SENTELIC_H +#define __SENTELIC_H + +/* Finger-sensing Pad information registers */ +#define FSP_REG_DEVICE_ID 0x00 +#define FSP_REG_VERSION 0x01 +#define FSP_REG_REVISION 0x04 +#define FSP_REG_TMOD_STATUS1 0x0B +#define FSP_BIT_NO_ROTATION BIT(3) +#define FSP_REG_PAGE_CTRL 0x0F + +/* Finger-sensing Pad control registers */ +#define FSP_REG_SYSCTL1 0x10 +#define FSP_BIT_EN_REG_CLK BIT(5) +#define FSP_REG_OPC_QDOWN 0x31 +#define FSP_BIT_EN_OPC_TAG BIT(7) +#define FSP_REG_OPTZ_XLO 0x34 +#define FSP_REG_OPTZ_XHI 0x35 +#define FSP_REG_OPTZ_YLO 0x36 +#define FSP_REG_OPTZ_YHI 0x37 +#define FSP_REG_SYSCTL5 0x40 +#define FSP_BIT_90_DEGREE BIT(0) +#define FSP_BIT_EN_MSID6 BIT(1) +#define FSP_BIT_EN_MSID7 BIT(2) +#define FSP_BIT_EN_MSID8 BIT(3) +#define FSP_BIT_EN_AUTO_MSID8 BIT(5) +#define FSP_BIT_EN_PKT_G0 BIT(6) + +#define FSP_REG_ONPAD_CTL 0x43 +#define FSP_BIT_ONPAD_ENABLE BIT(0) +#define FSP_BIT_ONPAD_FBBB BIT(1) +#define FSP_BIT_FIX_VSCR BIT(3) +#define FSP_BIT_FIX_HSCR BIT(5) +#define FSP_BIT_DRAG_LOCK BIT(6) + +/* Finger-sensing Pad packet formating related definitions */ + +/* absolute packet type */ +#define FSP_PKT_TYPE_NORMAL (0x00) +#define FSP_PKT_TYPE_ABS (0x01) +#define FSP_PKT_TYPE_NOTIFY (0x02) +#define FSP_PKT_TYPE_NORMAL_OPC (0x03) +#define FSP_PKT_TYPE_SHIFT (6) + +#ifdef __KERNEL__ + +struct fsp_data { + unsigned char ver; /* hardware version */ + unsigned char rev; /* hardware revison */ + unsigned char buttons; /* Number of buttons */ + unsigned int flags; +#define FSPDRV_FLAG_EN_OPC (0x001) /* enable on-pad clicking */ + + bool vscroll; /* Vertical scroll zone enabled */ + bool hscroll; /* Horizontal scroll zone enabled */ + + unsigned char last_reg; /* Last register we requested read from */ + unsigned char last_val; +}; + +#ifdef CONFIG_MOUSE_PS2_SENTELIC +extern int fsp_detect(struct psmouse *psmouse, int set_properties); +extern int fsp_init(struct psmouse *psmouse); +#else +inline int fsp_detect(struct psmouse *psmouse, int set_properties) +{ + return -ENOSYS; +} +inline int fsp_init(struct psmouse *psmouse) +{ + return -ENOSYS; +} +#endif + +#endif /* __KERNEL__ */ + +#endif /* !__SENTELIC_H */ diff --git a/drivers/input/mouse/vsxxxaa.c b/drivers/input/mouse/vsxxxaa.c index 404eedd5ffa..70111443678 100644 --- a/drivers/input/mouse/vsxxxaa.c +++ b/drivers/input/mouse/vsxxxaa.c @@ -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) diff --git a/drivers/input/serio/at32psif.c b/drivers/input/serio/at32psif.c index 41fda8c67b1..a6fb7a3dcc4 100644 --- a/drivers/input/serio/at32psif.c +++ b/drivers/input/serio/at32psif.c @@ -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"); diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c index 582245c497e..9f5c0506242 100644 --- a/drivers/input/serio/i8042.c +++ b/drivers/input/serio/i8042.c @@ -923,41 +923,27 @@ static void i8042_dritek_enable(void) #ifdef CONFIG_PM -static bool i8042_suspended; - /* - * Here we try to restore the original BIOS settings. We only want to - * do that once, when we really suspend, not when we taking memory - * snapshot for swsusp (in this case we'll perform required cleanup - * as part of shutdown process). + * Here we try to restore the original BIOS settings to avoid + * upsetting it. */ -static int i8042_suspend(struct platform_device *dev, pm_message_t state) +static int i8042_pm_reset(struct device *dev) { - if (!i8042_suspended && state.event == PM_EVENT_SUSPEND) - i8042_controller_reset(); - - i8042_suspended = state.event == PM_EVENT_SUSPEND || - state.event == PM_EVENT_FREEZE; + i8042_controller_reset(); return 0; } - /* - * Here we try to reset everything back to a state in which suspended + * Here we try to reset everything back to a state we had + * before suspending. */ -static int i8042_resume(struct platform_device *dev) +static int i8042_pm_restore(struct device *dev) { int error; -/* - * Do not bother with restoring state if we haven't suspened yet - */ - if (!i8042_suspended) - return 0; - error = i8042_controller_check(); if (error) return error; @@ -1001,11 +987,18 @@ static int i8042_resume(struct platform_device *dev) if (i8042_ports[I8042_KBD_PORT_NO].serio) i8042_enable_kbd_port(); - i8042_suspended = false; i8042_interrupt(0, NULL); return 0; } + +static const struct dev_pm_ops i8042_pm_ops = { + .suspend = i8042_pm_reset, + .resume = i8042_pm_restore, + .poweroff = i8042_pm_reset, + .restore = i8042_pm_restore, +}; + #endif /* CONFIG_PM */ /* @@ -1251,14 +1244,13 @@ static struct platform_driver i8042_driver = { .driver = { .name = "i8042", .owner = THIS_MODULE, +#ifdef CONFIG_PM + .pm = &i8042_pm_ops, +#endif }, .probe = i8042_probe, .remove = __devexit_p(i8042_remove), .shutdown = i8042_shutdown, -#ifdef CONFIG_PM - .suspend = i8042_suspend, - .resume = i8042_resume, -#endif }; static int __init i8042_init(void) diff --git a/drivers/input/serio/libps2.c b/drivers/input/serio/libps2.c index be5bbbb8ae4..3a95b508bf2 100644 --- a/drivers/input/serio/libps2.c +++ b/drivers/input/serio/libps2.c @@ -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); diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c index d66f4944f2a..0236f0d5fd9 100644 --- a/drivers/input/serio/serio.c +++ b/drivers/input/serio/serio.c @@ -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 }; diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 72e2712c7e2..87a1ae63bcc 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -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. diff --git a/drivers/input/touchscreen/atmel_tsadcc.c b/drivers/input/touchscreen/atmel_tsadcc.c index 055969e8be1..9c7fce4d74d 100644 --- a/drivers/input/touchscreen/atmel_tsadcc.c +++ b/drivers/input/touchscreen/atmel_tsadcc.c @@ -204,14 +204,14 @@ static int __devinit atmel_tsadcc_probe(struct platform_device *pdev) goto err_free_dev; } - if (!request_mem_region(res->start, res->end - res->start + 1, + if (!request_mem_region(res->start, resource_size(res), "atmel tsadcc regs")) { dev_err(&pdev->dev, "resources is unavailable.\n"); err = -EBUSY; goto err_free_dev; } - tsc_base = ioremap(res->start, res->end - res->start + 1); + tsc_base = ioremap(res->start, resource_size(res)); if (!tsc_base) { dev_err(&pdev->dev, "failed to map registers.\n"); err = -ENOMEM; @@ -286,7 +286,7 @@ err_free_irq: err_unmap_regs: iounmap(tsc_base); err_release_mem: - release_mem_region(res->start, res->end - res->start + 1); + release_mem_region(res->start, resource_size(res)); err_free_dev: input_free_device(ts_dev->input); err_free_mem: @@ -305,7 +305,7 @@ static int __devexit atmel_tsadcc_remove(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); iounmap(tsc_base); - release_mem_region(res->start, res->end - res->start + 1); + release_mem_region(res->start, resource_size(res)); clk_disable(ts_dev->clk); clk_put(ts_dev->clk); diff --git a/drivers/input/touchscreen/eeti_ts.c b/drivers/input/touchscreen/eeti_ts.c index 3ab92222a52..9029bd3f34e 100644 --- a/drivers/input/touchscreen/eeti_ts.c +++ b/drivers/input/touchscreen/eeti_ts.c @@ -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"); diff --git a/drivers/input/touchscreen/h3600_ts_input.c b/drivers/input/touchscreen/h3600_ts_input.c index 4d3139e2099..b4d7f63deff 100644 --- a/drivers/input/touchscreen/h3600_ts_input.c +++ b/drivers/input/touchscreen/h3600_ts_input.c @@ -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; } } diff --git a/drivers/input/touchscreen/mainstone-wm97xx.c b/drivers/input/touchscreen/mainstone-wm97xx.c index 4cc047a5116..8fc3b08deb3 100644 --- a/drivers/input/touchscreen/mainstone-wm97xx.c +++ b/drivers/input/touchscreen/mainstone-wm97xx.c @@ -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 @@ up: static int wm97xx_acc_startup(struct wm97xx *wm) { - int idx = 0; + int idx = 0, ret = 0; /* check we have a codec */ if (wm->ac97 == NULL) @@ -191,18 +194,40 @@ static int wm97xx_acc_startup(struct wm97xx *wm) "mainstone accelerated touchscreen driver, %d samples/sec\n", cinfo[sp_idx].speed); + /* IRQ driven touchscreen is used on Palm hardware */ + if (machine_is_palmt5() || machine_is_palmtx() || machine_is_palmld()) { + pen_int = 1; + irq = 27; + /* There is some obscure mutant of WM9712 interbred with WM9713 + * used on Palm HW */ + wm->variant = WM97xx_WM1613; + } else if (machine_is_mainstone() && pen_int) + irq = 4; + + if (irq) { + ret = gpio_request(irq, "Touchscreen IRQ"); + if (ret) + goto out; + + ret = gpio_direction_input(irq); + if (ret) { + gpio_free(irq); + goto out; + } + + wm->pen_irq = gpio_to_irq(irq); + set_irq_type(wm->pen_irq, IRQ_TYPE_EDGE_BOTH); + } else /* pen irq not supported */ + pen_int = 0; + /* codec specific irq config */ if (pen_int) { switch (wm->id) { case WM9705_ID2: - wm->pen_irq = IRQ_GPIO(4); - set_irq_type(IRQ_GPIO(4), IRQ_TYPE_EDGE_BOTH); break; case WM9712_ID2: case WM9713_ID2: - /* enable pen down interrupt */ /* use PEN_DOWN GPIO 13 to assert IRQ on GPIO line 2 */ - wm->pen_irq = MAINSTONE_AC97_IRQ; wm97xx_config_gpio(wm, WM97XX_GPIO_13, WM97XX_GPIO_IN, WM97XX_GPIO_POL_HIGH, WM97XX_GPIO_STICKY, @@ -220,23 +245,17 @@ static int wm97xx_acc_startup(struct wm97xx *wm) } } - return 0; +out: + return ret; } static void wm97xx_acc_shutdown(struct wm97xx *wm) { /* codec specific deconfig */ if (pen_int) { - switch (wm->id & 0xffff) { - case WM9705_ID2: - wm->pen_irq = 0; - break; - case WM9712_ID2: - case WM9713_ID2: - /* disable interrupt */ - wm->pen_irq = 0; - break; - } + if (irq) + gpio_free(irq); + wm->pen_irq = 0; } } diff --git a/drivers/input/touchscreen/tsc2007.c b/drivers/input/touchscreen/tsc2007.c index 880f58c6a7c..7ef0d1420d3 100644 --- a/drivers/input/touchscreen/tsc2007.c +++ b/drivers/input/touchscreen/tsc2007.c @@ -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); + + /* turn y- off, x+ on, then leave in lowpower */ + tc->x = tsc2007_xfer(tsc, READ_X); + + /* turn y+ off, x- on; we'll use formula #1 */ + tc->z1 = tsc2007_xfer(tsc, READ_Z1); + tc->z2 = tsc2007_xfer(tsc, READ_Z2); - x = ts->tc.x; - y = ts->tc.y; - z1 = ts->tc.z1; - z2 = ts->tc.z2; + /* Prepare for next touch reading - power down ADC, enable PENIRQ */ + tsc2007_xfer(tsc, PWRDOWN); +} + +static u32 tsc2007_calculate_pressure(struct tsc2007 *tsc, struct ts_event *tc) +{ + u32 rt = 0; /* range filtering */ - if (x == MAX_12BIT) - x = 0; + if (tc->x == MAX_12BIT) + tc->x = 0; - if (likely(x && z1)) { + if (likely(tc->x && tc->z1)) { /* compute touch pressure resistance using equation #1 */ - rt = z2; - rt -= z1; - rt *= x; - rt *= ts->x_plate_ohms; - rt /= z1; + rt = tc->z2 - tc->z1; + rt *= tc->x; + rt *= tsc->x_plate_ohms; + rt /= tc->z1; rt = (rt + 2047) >> 12; - } else - rt = 0; + } + + return rt; +} + +static void tsc2007_send_up_event(struct tsc2007 *tsc) +{ + struct input_dev *input = tsc->input; - /* Sample found inconsistent by debouncing or pressure is beyond - * the maximum. Don't report it to user space, repeat at least - * once more the measurement + dev_dbg(&tsc->client->dev, "UP\n"); + + input_report_key(input, BTN_TOUCH, 0); + input_report_abs(input, ABS_PRESSURE, 0); + input_sync(input); +} + +static void tsc2007_work(struct work_struct *work) +{ + struct tsc2007 *ts = + container_of(to_delayed_work(work), struct tsc2007, work); + struct ts_event tc; + u32 rt; + + /* + * NOTE: We can't rely on the pressure to determine the pen down + * state, even though this controller has a pressure sensor. + * The pressure value can fluctuate for quite a while after + * lifting the pen and in some cases may not even settle at the + * expected value. + * + * The only safe way to check for the pen up condition is in the + * work function by reading the pen signal state (it's a GPIO + * and IRQ). Unfortunately such callback is not always available, + * in that case we have rely on the pressure anyway. */ + if (ts->get_pendown_state) { + if (unlikely(!ts->get_pendown_state())) { + tsc2007_send_up_event(ts); + ts->pendown = false; + goto out; + } + + dev_dbg(&ts->client->dev, "pen is still down\n"); + } + + tsc2007_read_values(ts, &tc); + + rt = tsc2007_calculate_pressure(ts, &tc); if (rt > MAX_12BIT) { + /* + * Sample found inconsistent by debouncing or pressure is + * beyond the maximum. Don't report it to user space, + * repeat at least once more the measurement. + */ dev_dbg(&ts->client->dev, "ignored pressure %d\n", rt); + goto out; - hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_PERIOD), - HRTIMER_MODE_REL); - return; } - /* NOTE: We can't rely on the pressure to determine the pen down - * state, even this controller has a pressure sensor. The pressure - * value can fluctuate for quite a while after lifting the pen and - * in some cases may not even settle at the expected value. - * - * The only safe way to check for the pen up condition is in the - * timer by reading the pen signal state (it's a GPIO _and_ IRQ). - */ if (rt) { struct input_dev *input = ts->input; @@ -162,102 +202,74 @@ static void tsc2007_send_event(void *tsc) dev_dbg(&ts->client->dev, "DOWN\n"); input_report_key(input, BTN_TOUCH, 1); - ts->pendown = 1; + ts->pendown = true; } - input_report_abs(input, ABS_X, x); - input_report_abs(input, ABS_Y, y); + input_report_abs(input, ABS_X, tc.x); + input_report_abs(input, ABS_Y, tc.y); input_report_abs(input, ABS_PRESSURE, rt); input_sync(input); dev_dbg(&ts->client->dev, "point(%4d,%4d), pressure (%4u)\n", - x, y, rt); + tc.x, tc.y, rt); + + } else if (!ts->get_pendown_state && ts->pendown) { + /* + * We don't have callback to check pendown state, so we + * have to assume that since pressure reported is 0 the + * pen was lifted up. + */ + tsc2007_send_up_event(ts); + ts->pendown = false; } - hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_PERIOD), - HRTIMER_MODE_REL); -} - -static int tsc2007_read_values(struct tsc2007 *tsc) -{ - /* y- still on; turn on only y+ (and ADC) */ - tsc->tc.y = tsc2007_xfer(tsc, READ_Y); - - /* turn y- off, x+ on, then leave in lowpower */ - tsc->tc.x = tsc2007_xfer(tsc, READ_X); - - /* turn y+ off, x- on; we'll use formula #1 */ - tsc->tc.z1 = tsc2007_xfer(tsc, READ_Z1); - tsc->tc.z2 = tsc2007_xfer(tsc, READ_Z2); - - /* power down */ - tsc2007_xfer(tsc, PWRDOWN); - - return 0; -} - -static enum hrtimer_restart tsc2007_timer(struct hrtimer *handle) -{ - struct tsc2007 *ts = container_of(handle, struct tsc2007, timer); - unsigned long flags; - - spin_lock_irqsave(&ts->lock, flags); - - if (unlikely(!ts->get_pendown_state() && ts->pendown)) { - struct input_dev *input = ts->input; - - dev_dbg(&ts->client->dev, "UP\n"); - - input_report_key(input, BTN_TOUCH, 0); - input_report_abs(input, ABS_PRESSURE, 0); - input_sync(input); - - ts->pendown = 0; + out: + if (ts->pendown) + schedule_delayed_work(&ts->work, + msecs_to_jiffies(TS_POLL_PERIOD)); + else enable_irq(ts->irq); - } else { - /* pen is still down, continue with the measurement */ - dev_dbg(&ts->client->dev, "pen is still down\n"); - - tsc2007_read_values(ts); - tsc2007_send_event(ts); - } - - spin_unlock_irqrestore(&ts->lock, flags); - - return HRTIMER_NORESTART; } static irqreturn_t tsc2007_irq(int irq, void *handle) { struct tsc2007 *ts = handle; - unsigned long flags; - - spin_lock_irqsave(&ts->lock, flags); - if (likely(ts->get_pendown_state())) { + if (!ts->get_pendown_state || likely(ts->get_pendown_state())) { disable_irq_nosync(ts->irq); - hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_DELAY), - HRTIMER_MODE_REL); + schedule_delayed_work(&ts->work, + msecs_to_jiffies(TS_POLL_DELAY)); } if (ts->clear_penirq) ts->clear_penirq(); - spin_unlock_irqrestore(&ts->lock, flags); - return IRQ_HANDLED; } -static int tsc2007_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static void tsc2007_free_irq(struct tsc2007 *ts) +{ + free_irq(ts->irq, ts); + if (cancel_delayed_work_sync(&ts->work)) { + /* + * Work was pending, therefore we need to enable + * IRQ here to balance the disable_irq() done in the + * interrupt handler. + */ + enable_irq(ts->irq); + } +} + +static int __devinit tsc2007_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct tsc2007 *ts; struct tsc2007_platform_data *pdata = pdata = client->dev.platform_data; struct input_dev *input_dev; int err; - if (!pdata || !pdata->get_pendown_state) { + if (!pdata) { dev_err(&client->dev, "platform data is required!\n"); return -EINVAL; } @@ -274,22 +286,15 @@ static int tsc2007_probe(struct i2c_client *client, } ts->client = client; - i2c_set_clientdata(client, ts); - + ts->irq = client->irq; ts->input = input_dev; - - hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); - ts->timer.function = tsc2007_timer; - - spin_lock_init(&ts->lock); + INIT_DELAYED_WORK(&ts->work, tsc2007_work); ts->model = pdata->model; ts->x_plate_ohms = pdata->x_plate_ohms; ts->get_pendown_state = pdata->get_pendown_state; ts->clear_penirq = pdata->clear_penirq; - pdata->init_platform_hw(); - snprintf(ts->phys, sizeof(ts->phys), "%s/input0", dev_name(&client->dev)); @@ -304,9 +309,8 @@ static int tsc2007_probe(struct i2c_client *client, input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, 0, 0); input_set_abs_params(input_dev, ABS_PRESSURE, 0, MAX_12BIT, 0, 0); - tsc2007_read_values(ts); - - ts->irq = client->irq; + if (pdata->init_platform_hw) + pdata->init_platform_hw(); err = request_irq(ts->irq, tsc2007_irq, 0, client->dev.driver->name, ts); @@ -315,33 +319,39 @@ static int tsc2007_probe(struct i2c_client *client, goto err_free_mem; } + /* Prepare for touch readings - power down ADC and enable PENIRQ */ + err = tsc2007_xfer(ts, PWRDOWN); + if (err < 0) + goto err_free_irq; + err = input_register_device(input_dev); if (err) goto err_free_irq; - dev_info(&client->dev, "registered with irq (%d)\n", ts->irq); + i2c_set_clientdata(client, ts); return 0; err_free_irq: - free_irq(ts->irq, ts); - hrtimer_cancel(&ts->timer); + tsc2007_free_irq(ts); + if (pdata->exit_platform_hw) + pdata->exit_platform_hw(); err_free_mem: input_free_device(input_dev); kfree(ts); return err; } -static int tsc2007_remove(struct i2c_client *client) +static int __devexit tsc2007_remove(struct i2c_client *client) { struct tsc2007 *ts = i2c_get_clientdata(client); - struct tsc2007_platform_data *pdata; + struct tsc2007_platform_data *pdata = client->dev.platform_data; - pdata = client->dev.platform_data; - pdata->exit_platform_hw(); + tsc2007_free_irq(ts); + + if (pdata->exit_platform_hw) + pdata->exit_platform_hw(); - free_irq(ts->irq, ts); - hrtimer_cancel(&ts->timer); input_unregister_device(ts->input); kfree(ts); @@ -362,7 +372,7 @@ static struct i2c_driver tsc2007_driver = { }, .id_table = tsc2007_idtable, .probe = tsc2007_probe, - .remove = tsc2007_remove, + .remove = __devexit_p(tsc2007_remove), }; static int __init tsc2007_init(void) diff --git a/drivers/input/touchscreen/ucb1400_ts.c b/drivers/input/touchscreen/ucb1400_ts.c index 3a7a58222f8..095f84b1f56 100644 --- a/drivers/input/touchscreen/ucb1400_ts.c +++ b/drivers/input/touchscreen/ucb1400_ts.c @@ -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); /* diff --git a/drivers/input/touchscreen/usbtouchscreen.c b/drivers/input/touchscreen/usbtouchscreen.c index fb7cb9bdfbd..68ece5801a5 100644 --- a/drivers/input/touchscreen/usbtouchscreen.c +++ b/drivers/input/touchscreen/usbtouchscreen.c @@ -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,11 +194,51 @@ 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 }; diff --git a/drivers/input/touchscreen/w90p910_ts.c b/drivers/input/touchscreen/w90p910_ts.c index 6071f588257..dc4c9d6b67c 100644 --- a/drivers/input/touchscreen/w90p910_ts.c +++ b/drivers/input/touchscreen/w90p910_ts.c @@ -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); diff --git a/drivers/input/touchscreen/wm97xx-core.c b/drivers/input/touchscreen/wm97xx-core.c index 2957d48e004..252eb11fe9d 100644 --- a/drivers/input/touchscreen/wm97xx-core.c +++ b/drivers/input/touchscreen/wm97xx-core.c @@ -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) { diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index f99bc7f089f..a7eb7277b10 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -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, diff --git a/include/linux/device.h b/include/linux/device.h index aebb81036db..a2864297505 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -62,7 +62,7 @@ struct bus_type { int (*suspend)(struct device *dev, pm_message_t state); int (*resume)(struct device *dev); - struct dev_pm_ops *pm; + const struct dev_pm_ops *pm; struct bus_type_private *p; }; @@ -132,7 +132,7 @@ struct device_driver { int (*resume) (struct device *dev); struct attribute_group **groups; - struct dev_pm_ops *pm; + const struct dev_pm_ops *pm; struct driver_private *p; }; @@ -200,7 +200,8 @@ struct class { int (*suspend)(struct device *dev, pm_message_t state); int (*resume)(struct device *dev); - struct dev_pm_ops *pm; + const struct dev_pm_ops *pm; + struct class_private *p; }; @@ -291,7 +292,7 @@ struct device_type { char *(*nodename)(struct device *dev); void (*release)(struct device *dev); - struct dev_pm_ops *pm; + const struct dev_pm_ops *pm; }; /* interface for exporting device attributes */ diff --git a/include/linux/input/eeti_ts.h b/include/linux/input/eeti_ts.h new file mode 100644 index 00000000000..f875b316249 --- /dev/null +++ b/include/linux/input/eeti_ts.h @@ -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 */ + diff --git a/include/linux/libps2.h b/include/linux/libps2.h index b94534b7e26..fcf5fbe6a50 100644 --- a/include/linux/libps2.h +++ b/include/linux/libps2.h @@ -44,6 +44,7 @@ struct ps2dev { void ps2_init(struct ps2dev *ps2dev, struct serio *serio); int ps2_sendbyte(struct ps2dev *ps2dev, unsigned char byte, int timeout); void ps2_drain(struct ps2dev *ps2dev, int maxbytes, int timeout); +int __ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command); int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command); int ps2_handle_ack(struct ps2dev *ps2dev, unsigned char data); int ps2_handle_response(struct ps2dev *ps2dev, unsigned char data); diff --git a/include/linux/serio.h b/include/linux/serio.h index 126d24c9eaa..a640bc2afe7 100644 --- a/include/linux/serio.h +++ b/include/linux/serio.h @@ -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; diff --git a/include/linux/wm97xx.h b/include/linux/wm97xx.h index 6f69968eab2..0c9878123d5 100644 --- a/include/linux/wm97xx.h +++ b/include/linux/wm97xx.h @@ -16,6 +16,12 @@ #include <linux/platform_device.h> /* + * WM97xx variants + */ +#define WM97xx_GENERIC 0x0000 +#define WM97xx_WM1613 0x1613 + +/* * WM97xx AC97 Touchscreen registers */ #define AC97_WM97XX_DIGITISER1 0x76 @@ -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 */ }; |