Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input: (62 commits) Input: atkbd - release previously reserved keycodes 248 - 254 Input: add KEY_WPS_BUTTON definition Input: ads7846 - add regulator support Input: winbond-cir - fix suspend/resume Input: gamecon - use pr_err() and friends Input: gamecon - constify some of the setup structures Input: gamecon - simplify pad type handling Input: gamecon - simplify coordinate calculation for PSX Input: gamecon - fix some formatting issues Input: gamecon - add rumble support for N64 pads Input: wacom - add device type to device name string Input: s3c24xx_ts - report touch only when stylus is down Input: s3c24xx_ts - re-enable IRQ on resume Input: wacom - constify product features data Input: wacom - use per-device instance of wacom_features Input: sh_keysc - enable building on SH-Mobile ARM Input: wacom - get features from driver info Input: rotary-encoder - set gpio direction for each requested gpio Input: sh_keysc - update the driver with mode 6 Input: sh_keysc - switch to using bitmaps ...
This commit is contained in:
commit
8724fdb53d
53 changed files with 3260 additions and 1344 deletions
|
|
@ -538,3 +538,26 @@ Why: Duplicate functionality with the gspca_zc3xx driver, zc0301 only
|
||||||
sensors) wich are also supported by the gspca_zc3xx driver
|
sensors) wich are also supported by the gspca_zc3xx driver
|
||||||
(which supports 53 USB-ID's in total)
|
(which supports 53 USB-ID's in total)
|
||||||
Who: Hans de Goede <hdegoede@redhat.com>
|
Who: Hans de Goede <hdegoede@redhat.com>
|
||||||
|
|
||||||
|
----------------------------
|
||||||
|
|
||||||
|
What: corgikbd, spitzkbd, tosakbd driver
|
||||||
|
When: 2.6.35
|
||||||
|
Files: drivers/input/keyboard/{corgi,spitz,tosa}kbd.c
|
||||||
|
Why: We now have a generic GPIO based matrix keyboard driver that
|
||||||
|
are fully capable of handling all the keys on these devices.
|
||||||
|
The original drivers manipulate the GPIO registers directly
|
||||||
|
and so are difficult to maintain.
|
||||||
|
Who: Eric Miao <eric.y.miao@gmail.com>
|
||||||
|
|
||||||
|
----------------------------
|
||||||
|
|
||||||
|
What: corgi_ssp and corgi_ts driver
|
||||||
|
When: 2.6.35
|
||||||
|
Files: arch/arm/mach-pxa/corgi_ssp.c, drivers/input/touchscreen/corgi_ts.c
|
||||||
|
Why: The corgi touchscreen is now deprecated in favour of the generic
|
||||||
|
ads7846.c driver. The noise reduction technique used in corgi_ts.c,
|
||||||
|
that's to wait till vsync before ADC sampling, is also integrated into
|
||||||
|
ads7846 driver now. Provided that the original driver is not generic
|
||||||
|
and is difficult to maintain, it will be removed later.
|
||||||
|
Who: Eric Miao <eric.y.miao@gmail.com>
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
Copyright (C) 2002-2008 Sentelic Corporation.
|
Copyright (C) 2002-2010 Sentelic Corporation.
|
||||||
Last update: Oct-31-2008
|
Last update: Jan-13-2010
|
||||||
|
|
||||||
==============================================================================
|
==============================================================================
|
||||||
* Finger Sensing Pad Intellimouse Mode(scrolling wheel, 4th and 5th buttons)
|
* Finger Sensing Pad Intellimouse Mode(scrolling wheel, 4th and 5th buttons)
|
||||||
|
|
@ -44,7 +44,7 @@ B) MSID 6: Horizontal and Vertical scrolling.
|
||||||
Packet 1
|
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
|
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|---------------|
|
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|
|
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|r|l|u|d|
|
||||||
|---------------| |---------------| |---------------| |---------------|
|
|---------------| |---------------| |---------------| |---------------|
|
||||||
|
|
||||||
Byte 1: Bit7 => Y overflow
|
Byte 1: Bit7 => Y overflow
|
||||||
|
|
@ -59,15 +59,15 @@ Byte 2: X Movement(9-bit 2's complement integers)
|
||||||
Byte 3: Y 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.
|
Byte 4: Bit0 => the Vertical scrolling movement downward.
|
||||||
Bit1 => the Vertical scrolling movement upward.
|
Bit1 => the Vertical scrolling movement upward.
|
||||||
Bit2 => the Vertical scrolling movement rightward.
|
Bit2 => the Horizontal scrolling movement leftward.
|
||||||
Bit3 => the Vertical scrolling movement leftward.
|
Bit3 => the Horizontal scrolling movement rightward.
|
||||||
Bit4 => 1 = 4th mouse button is pressed, Forward one page.
|
Bit4 => 1 = 4th mouse button is pressed, Forward one page.
|
||||||
0 = 4th mouse button is not pressed.
|
0 = 4th mouse button is not pressed.
|
||||||
Bit5 => 1 = 5th mouse button is pressed, Backward one page.
|
Bit5 => 1 = 5th mouse button is pressed, Backward one page.
|
||||||
0 = 5th mouse button is not pressed.
|
0 = 5th mouse button is not pressed.
|
||||||
|
|
||||||
C) MSID 7:
|
C) MSID 7:
|
||||||
# FSP uses 2 packets(8 Bytes) data to represent Absolute Position
|
# FSP uses 2 packets (8 Bytes) to represent Absolute Position.
|
||||||
so we have PACKET NUMBER to identify packets.
|
so we have PACKET NUMBER to identify packets.
|
||||||
If PACKET NUMBER is 0, the packet is Packet 1.
|
If PACKET NUMBER is 0, the packet is Packet 1.
|
||||||
If PACKET NUMBER is 1, the packet is Packet 2.
|
If PACKET NUMBER is 1, the packet is Packet 2.
|
||||||
|
|
@ -129,7 +129,7 @@ Byte 3: Message Type => 0x00 (Disabled)
|
||||||
Byte 4: Bit7~Bit0 => Don't Care
|
Byte 4: Bit7~Bit0 => Don't Care
|
||||||
|
|
||||||
==============================================================================
|
==============================================================================
|
||||||
* Absolute position for STL3888-A0.
|
* Absolute position for STL3888-Ax.
|
||||||
==============================================================================
|
==============================================================================
|
||||||
Packet 1 (ABSOLUTE POSITION)
|
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
|
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
|
||||||
|
|
@ -179,14 +179,14 @@ Byte 4: Bit1~Bit0 => Y coordinate (xpos[1:0])
|
||||||
Bit5~Bit4 => y2_g
|
Bit5~Bit4 => y2_g
|
||||||
Bit7~Bit6 => x2_g
|
Bit7~Bit6 => x2_g
|
||||||
|
|
||||||
Notify Packet for STL3888-A0
|
Notify Packet for STL3888-Ax
|
||||||
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
|
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|---------------|
|
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|
|
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
|
Byte 1: Bit7~Bit6 => 00, Normal data packet
|
||||||
=> 01, Absolute coordination packet
|
=> 01, Absolute coordinates packet
|
||||||
=> 10, Notify packet
|
=> 10, Notify packet
|
||||||
Bit5 => 1
|
Bit5 => 1
|
||||||
Bit4 => when in absolute coordinates mode (valid when EN_PKT_GO is 1):
|
Bit4 => when in absolute coordinates mode (valid when EN_PKT_GO is 1):
|
||||||
|
|
@ -205,7 +205,7 @@ Byte 4: Bit7 => scroll right button
|
||||||
Bit6 => scroll left button
|
Bit6 => scroll left button
|
||||||
Bit5 => scroll down button
|
Bit5 => scroll down button
|
||||||
Bit4 => scroll up button
|
Bit4 => scroll up button
|
||||||
* Note that if gesture and additional button (Bit4~Bit7)
|
* Note that if gesture and additional buttoni (Bit4~Bit7)
|
||||||
happen at the same time, the button information will not
|
happen at the same time, the button information will not
|
||||||
be sent.
|
be sent.
|
||||||
Bit3~Bit0 => Reserved
|
Bit3~Bit0 => Reserved
|
||||||
|
|
@ -213,7 +213,98 @@ Byte 4: Bit7 => scroll right button
|
||||||
Sample sequence of Multi-finger, Multi-coordinate mode:
|
Sample sequence of Multi-finger, Multi-coordinate mode:
|
||||||
|
|
||||||
notify packet (valid bit == 1), abs pkt 1, abs pkt 2, abs pkt 1,
|
notify packet (valid bit == 1), abs pkt 1, abs pkt 2, abs pkt 1,
|
||||||
abs pkt 2, ..., notify packet(valid bit == 0)
|
abs pkt 2, ..., notify packet (valid bit == 0)
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
* Absolute position for STL3888-B0.
|
||||||
|
==============================================================================
|
||||||
|
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|F|1|0|R|L| 2 |X|X|X|X|X|X|X|X| 3 |Y|Y|Y|Y|Y|Y|Y|Y| 4 |r|l|u|d|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 => finger up/down information. 1: finger down, 0: finger up.
|
||||||
|
Bit3 => 1
|
||||||
|
Bit2 => finger index, 0 is the first finger, 1 is the second finger.
|
||||||
|
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 down button
|
||||||
|
Bit5 => scroll up button
|
||||||
|
Bit6 => scroll left button
|
||||||
|
Bit7 => scroll right button
|
||||||
|
|
||||||
|
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|F|1|1|R|L| 2 |X|X|X|X|X|X|X|X| 3 |Y|Y|Y|Y|Y|Y|Y|Y| 4 |r|l|u|d|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 => finger up/down information. 1: finger down, 0: finger up.
|
||||||
|
Bit3 => 1
|
||||||
|
Bit2 => finger index, 0 is the first finger, 1 is the second finger.
|
||||||
|
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 down button
|
||||||
|
Bit5 => scroll up button
|
||||||
|
Bit6 => scroll left button
|
||||||
|
Bit7 => scroll right button
|
||||||
|
|
||||||
|
Notify Packet for STL3888-B0
|
||||||
|
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|u|d|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 coordinate 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 up button
|
||||||
|
Bit4 => scroll down 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
|
* FSP Enable/Disable packet
|
||||||
|
|
@ -409,7 +500,8 @@ offset width default r/w name
|
||||||
0: read only, 1: read/write enable
|
0: read only, 1: read/write enable
|
||||||
(Note that following registers does not require clock gating being
|
(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
|
enabled prior to write: 05 06 07 08 09 0c 0f 10 11 12 16 17 18 23 2e
|
||||||
40 41 42 43.)
|
40 41 42 43. In addition to that, this bit must be 1 when gesture
|
||||||
|
mode is enabled)
|
||||||
|
|
||||||
0x31 RW on-pad command detection
|
0x31 RW on-pad command detection
|
||||||
bit7 0 RW on-pad command left button down tag
|
bit7 0 RW on-pad command left button down tag
|
||||||
|
|
@ -463,6 +555,10 @@ offset width default r/w name
|
||||||
absolute coordinates; otherwise, host only receives packets with
|
absolute coordinates; otherwise, host only receives packets with
|
||||||
relative coordinate.)
|
relative coordinate.)
|
||||||
|
|
||||||
|
bit7 0 RW EN_PS2_F2: PS/2 gesture mode 2nd
|
||||||
|
finger packet enable
|
||||||
|
0: disable, 1: enable
|
||||||
|
|
||||||
0x43 RW on-pad control
|
0x43 RW on-pad control
|
||||||
bit0 0 RW on-pad control enable
|
bit0 0 RW on-pad control enable
|
||||||
0: disable, 1: enable
|
0: disable, 1: enable
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,8 @@
|
||||||
#ifndef __ASM_ARCH_EP93XX_KEYPAD_H
|
#ifndef __ASM_ARCH_EP93XX_KEYPAD_H
|
||||||
#define __ASM_ARCH_EP93XX_KEYPAD_H
|
#define __ASM_ARCH_EP93XX_KEYPAD_H
|
||||||
|
|
||||||
|
struct matrix_keymap_data;
|
||||||
|
|
||||||
/* flags for the ep93xx_keypad driver */
|
/* flags for the ep93xx_keypad driver */
|
||||||
#define EP93XX_KEYPAD_DISABLE_3_KEY (1<<0) /* disable 3-key reset */
|
#define EP93XX_KEYPAD_DISABLE_3_KEY (1<<0) /* disable 3-key reset */
|
||||||
#define EP93XX_KEYPAD_DIAG_MODE (1<<1) /* diagnostic mode */
|
#define EP93XX_KEYPAD_DIAG_MODE (1<<1) /* diagnostic mode */
|
||||||
|
|
@ -15,15 +17,13 @@
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct ep93xx_keypad_platform_data - platform specific device structure
|
* struct ep93xx_keypad_platform_data - platform specific device structure
|
||||||
* @matrix_key_map: array of keycodes defining the keypad matrix
|
* @keymap_data: pointer to &matrix_keymap_data
|
||||||
* @matrix_key_map_size: ARRAY_SIZE(matrix_key_map)
|
|
||||||
* @debounce: debounce start count; terminal count is 0xff
|
* @debounce: debounce start count; terminal count is 0xff
|
||||||
* @prescale: row/column counter pre-scaler load value
|
* @prescale: row/column counter pre-scaler load value
|
||||||
* @flags: see above
|
* @flags: see above
|
||||||
*/
|
*/
|
||||||
struct ep93xx_keypad_platform_data {
|
struct ep93xx_keypad_platform_data {
|
||||||
unsigned int *matrix_key_map;
|
struct matrix_keymap_data *keymap_data;
|
||||||
int matrix_key_map_size;
|
|
||||||
unsigned int debounce;
|
unsigned int debounce;
|
||||||
unsigned int prescale;
|
unsigned int prescale;
|
||||||
unsigned int flags;
|
unsigned int flags;
|
||||||
|
|
|
||||||
|
|
@ -1185,11 +1185,6 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw)
|
||||||
|
|
||||||
rep = (down == 2);
|
rep = (down == 2);
|
||||||
|
|
||||||
#ifdef CONFIG_MAC_EMUMOUSEBTN
|
|
||||||
if (mac_hid_mouse_emulate_buttons(1, keycode, down))
|
|
||||||
return;
|
|
||||||
#endif /* CONFIG_MAC_EMUMOUSEBTN */
|
|
||||||
|
|
||||||
if ((raw_mode = (kbd->kbdmode == VC_RAW)) && !hw_raw)
|
if ((raw_mode = (kbd->kbdmode == VC_RAW)) && !hw_raw)
|
||||||
if (emulate_raw(vc, keycode, !down << 7))
|
if (emulate_raw(vc, keycode, !down << 7))
|
||||||
if (keycode < BTN_MISC && printk_ratelimit())
|
if (keycode < BTN_MISC && printk_ratelimit())
|
||||||
|
|
@ -1328,6 +1323,21 @@ static void kbd_event(struct input_handle *handle, unsigned int event_type,
|
||||||
schedule_console_callback();
|
schedule_console_callback();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool kbd_match(struct input_handler *handler, struct input_dev *dev)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (test_bit(EV_SND, dev->evbit))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (test_bit(EV_KEY, dev->evbit))
|
||||||
|
for (i = KEY_RESERVED; i < BTN_MISC; i++)
|
||||||
|
if (test_bit(i, dev->keybit))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* When a keyboard (or other input device) is found, the kbd_connect
|
* When a keyboard (or other input device) is found, the kbd_connect
|
||||||
* function is called. The function then looks at the device, and if it
|
* function is called. The function then looks at the device, and if it
|
||||||
|
|
@ -1339,14 +1349,6 @@ static int kbd_connect(struct input_handler *handler, struct input_dev *dev,
|
||||||
{
|
{
|
||||||
struct input_handle *handle;
|
struct input_handle *handle;
|
||||||
int error;
|
int error;
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = KEY_RESERVED; i < BTN_MISC; i++)
|
|
||||||
if (test_bit(i, dev->keybit))
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (i == BTN_MISC && !test_bit(EV_SND, dev->evbit))
|
|
||||||
return -ENODEV;
|
|
||||||
|
|
||||||
handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL);
|
handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL);
|
||||||
if (!handle)
|
if (!handle)
|
||||||
|
|
@ -1412,6 +1414,7 @@ MODULE_DEVICE_TABLE(input, kbd_ids);
|
||||||
|
|
||||||
static struct input_handler kbd_handler = {
|
static struct input_handler kbd_handler = {
|
||||||
.event = kbd_event,
|
.event = kbd_event,
|
||||||
|
.match = kbd_match,
|
||||||
.connect = kbd_connect,
|
.connect = kbd_connect,
|
||||||
.disconnect = kbd_disconnect,
|
.disconnect = kbd_disconnect,
|
||||||
.start = kbd_start,
|
.start = kbd_start,
|
||||||
|
|
|
||||||
|
|
@ -278,6 +278,8 @@ static int evdev_open(struct inode *inode, struct file *file)
|
||||||
goto err_free_client;
|
goto err_free_client;
|
||||||
|
|
||||||
file->private_data = client;
|
file->private_data = client;
|
||||||
|
nonseekable_open(inode, file);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err_free_client:
|
err_free_client:
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@ struct emu {
|
||||||
int size;
|
int size;
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct pci_device_id emu_tbl[] = {
|
static const struct pci_device_id emu_tbl[] = {
|
||||||
|
|
||||||
{ 0x1102, 0x7002, PCI_ANY_ID, PCI_ANY_ID }, /* SB Live gameport */
|
{ 0x1102, 0x7002, PCI_ANY_ID, PCI_ANY_ID }, /* SB Live gameport */
|
||||||
{ 0x1102, 0x7003, PCI_ANY_ID, PCI_ANY_ID }, /* Audigy gameport */
|
{ 0x1102, 0x7003, PCI_ANY_ID, PCI_ANY_ID }, /* Audigy gameport */
|
||||||
|
|
|
||||||
|
|
@ -140,7 +140,7 @@ static void __devexit fm801_gp_remove(struct pci_dev *pci)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct pci_device_id fm801_gp_id_table[] = {
|
static const struct pci_device_id fm801_gp_id_table[] = {
|
||||||
{ PCI_VENDOR_ID_FORTEMEDIA, PCI_DEVICE_ID_FM801_GP, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
|
{ PCI_VENDOR_ID_FORTEMEDIA, PCI_DEVICE_ID_FM801_GP, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
|
||||||
{ 0 }
|
{ 0 }
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,8 @@
|
||||||
* the Free Software Foundation.
|
* the Free Software Foundation.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||||
|
|
||||||
#include <linux/stddef.h>
|
#include <linux/stddef.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/ioport.h>
|
#include <linux/ioport.h>
|
||||||
|
|
@ -190,9 +192,8 @@ static int gameport_bind_driver(struct gameport *gameport, struct gameport_drive
|
||||||
|
|
||||||
error = device_bind_driver(&gameport->dev);
|
error = device_bind_driver(&gameport->dev);
|
||||||
if (error) {
|
if (error) {
|
||||||
printk(KERN_WARNING
|
dev_warn(&gameport->dev,
|
||||||
"gameport: device_bind_driver() failed "
|
"device_bind_driver() failed for %s (%s) and %s, error: %d\n",
|
||||||
"for %s (%s) and %s, error: %d\n",
|
|
||||||
gameport->phys, gameport->name,
|
gameport->phys, gameport->name,
|
||||||
drv->description, error);
|
drv->description, error);
|
||||||
drv->disconnect(gameport);
|
drv->disconnect(gameport);
|
||||||
|
|
@ -209,8 +210,8 @@ static void gameport_find_driver(struct gameport *gameport)
|
||||||
|
|
||||||
error = device_attach(&gameport->dev);
|
error = device_attach(&gameport->dev);
|
||||||
if (error < 0)
|
if (error < 0)
|
||||||
printk(KERN_WARNING
|
dev_warn(&gameport->dev,
|
||||||
"gameport: device_attach() failed for %s (%s), error: %d\n",
|
"device_attach() failed for %s (%s), error: %d\n",
|
||||||
gameport->phys, gameport->name, error);
|
gameport->phys, gameport->name, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -262,16 +263,13 @@ static int gameport_queue_event(void *object, struct module *owner,
|
||||||
|
|
||||||
event = kmalloc(sizeof(struct gameport_event), GFP_ATOMIC);
|
event = kmalloc(sizeof(struct gameport_event), GFP_ATOMIC);
|
||||||
if (!event) {
|
if (!event) {
|
||||||
printk(KERN_ERR
|
pr_err("Not enough memory to queue event %d\n", event_type);
|
||||||
"gameport: Not enough memory to queue event %d\n",
|
|
||||||
event_type);
|
|
||||||
retval = -ENOMEM;
|
retval = -ENOMEM;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!try_module_get(owner)) {
|
if (!try_module_get(owner)) {
|
||||||
printk(KERN_WARNING
|
pr_warning("Can't get module reference, dropping event %d\n",
|
||||||
"gameport: Can't get module reference, dropping event %d\n",
|
|
||||||
event_type);
|
event_type);
|
||||||
kfree(event);
|
kfree(event);
|
||||||
retval = -EINVAL;
|
retval = -EINVAL;
|
||||||
|
|
@ -298,14 +296,12 @@ static void gameport_free_event(struct gameport_event *event)
|
||||||
|
|
||||||
static void gameport_remove_duplicate_events(struct gameport_event *event)
|
static void gameport_remove_duplicate_events(struct gameport_event *event)
|
||||||
{
|
{
|
||||||
struct list_head *node, *next;
|
struct gameport_event *e, *next;
|
||||||
struct gameport_event *e;
|
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
spin_lock_irqsave(&gameport_event_lock, flags);
|
spin_lock_irqsave(&gameport_event_lock, flags);
|
||||||
|
|
||||||
list_for_each_safe(node, next, &gameport_event_list) {
|
list_for_each_entry_safe(e, next, &gameport_event_list, node) {
|
||||||
e = list_entry(node, struct gameport_event, node);
|
|
||||||
if (event->object == e->object) {
|
if (event->object == e->object) {
|
||||||
/*
|
/*
|
||||||
* If this event is of different type we should not
|
* If this event is of different type we should not
|
||||||
|
|
@ -315,7 +311,7 @@ static void gameport_remove_duplicate_events(struct gameport_event *event)
|
||||||
if (event->type != e->type)
|
if (event->type != e->type)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
list_del_init(node);
|
list_del_init(&e->node);
|
||||||
gameport_free_event(e);
|
gameport_free_event(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -325,23 +321,18 @@ static void gameport_remove_duplicate_events(struct gameport_event *event)
|
||||||
|
|
||||||
static struct gameport_event *gameport_get_event(void)
|
static struct gameport_event *gameport_get_event(void)
|
||||||
{
|
{
|
||||||
struct gameport_event *event;
|
struct gameport_event *event = NULL;
|
||||||
struct list_head *node;
|
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
spin_lock_irqsave(&gameport_event_lock, flags);
|
spin_lock_irqsave(&gameport_event_lock, flags);
|
||||||
|
|
||||||
if (list_empty(&gameport_event_list)) {
|
if (!list_empty(&gameport_event_list)) {
|
||||||
spin_unlock_irqrestore(&gameport_event_lock, flags);
|
event = list_first_entry(&gameport_event_list,
|
||||||
return NULL;
|
struct gameport_event, node);
|
||||||
|
list_del_init(&event->node);
|
||||||
}
|
}
|
||||||
|
|
||||||
node = gameport_event_list.next;
|
|
||||||
event = list_entry(node, struct gameport_event, node);
|
|
||||||
list_del_init(node);
|
|
||||||
|
|
||||||
spin_unlock_irqrestore(&gameport_event_lock, flags);
|
spin_unlock_irqrestore(&gameport_event_lock, flags);
|
||||||
|
|
||||||
return event;
|
return event;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -360,6 +351,7 @@ static void gameport_handle_event(void)
|
||||||
if ((event = gameport_get_event())) {
|
if ((event = gameport_get_event())) {
|
||||||
|
|
||||||
switch (event->type) {
|
switch (event->type) {
|
||||||
|
|
||||||
case GAMEPORT_REGISTER_PORT:
|
case GAMEPORT_REGISTER_PORT:
|
||||||
gameport_add_port(event->object);
|
gameport_add_port(event->object);
|
||||||
break;
|
break;
|
||||||
|
|
@ -367,9 +359,6 @@ static void gameport_handle_event(void)
|
||||||
case GAMEPORT_ATTACH_DRIVER:
|
case GAMEPORT_ATTACH_DRIVER:
|
||||||
gameport_attach_driver(event->object);
|
gameport_attach_driver(event->object);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
gameport_remove_duplicate_events(event);
|
gameport_remove_duplicate_events(event);
|
||||||
|
|
@ -385,16 +374,14 @@ static void gameport_handle_event(void)
|
||||||
*/
|
*/
|
||||||
static void gameport_remove_pending_events(void *object)
|
static void gameport_remove_pending_events(void *object)
|
||||||
{
|
{
|
||||||
struct list_head *node, *next;
|
struct gameport_event *event, *next;
|
||||||
struct gameport_event *event;
|
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
spin_lock_irqsave(&gameport_event_lock, flags);
|
spin_lock_irqsave(&gameport_event_lock, flags);
|
||||||
|
|
||||||
list_for_each_safe(node, next, &gameport_event_list) {
|
list_for_each_entry_safe(event, next, &gameport_event_list, node) {
|
||||||
event = list_entry(node, struct gameport_event, node);
|
|
||||||
if (event->object == object) {
|
if (event->object == object) {
|
||||||
list_del_init(node);
|
list_del_init(&event->node);
|
||||||
gameport_free_event(event);
|
gameport_free_event(event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -441,7 +428,6 @@ static int gameport_thread(void *nothing)
|
||||||
kthread_should_stop() || !list_empty(&gameport_event_list));
|
kthread_should_stop() || !list_empty(&gameport_event_list));
|
||||||
} while (!kthread_should_stop());
|
} while (!kthread_should_stop());
|
||||||
|
|
||||||
printk(KERN_DEBUG "gameport: kgameportd exiting\n");
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -453,6 +439,7 @@ static int gameport_thread(void *nothing)
|
||||||
static ssize_t gameport_show_description(struct device *dev, struct device_attribute *attr, char *buf)
|
static ssize_t gameport_show_description(struct device *dev, struct device_attribute *attr, char *buf)
|
||||||
{
|
{
|
||||||
struct gameport *gameport = to_gameport_port(dev);
|
struct gameport *gameport = to_gameport_port(dev);
|
||||||
|
|
||||||
return sprintf(buf, "%s\n", gameport->name);
|
return sprintf(buf, "%s\n", gameport->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -521,7 +508,8 @@ static void gameport_init_port(struct gameport *gameport)
|
||||||
|
|
||||||
mutex_init(&gameport->drv_mutex);
|
mutex_init(&gameport->drv_mutex);
|
||||||
device_initialize(&gameport->dev);
|
device_initialize(&gameport->dev);
|
||||||
dev_set_name(&gameport->dev, "gameport%lu", (unsigned long)atomic_inc_return(&gameport_no) - 1);
|
dev_set_name(&gameport->dev, "gameport%lu",
|
||||||
|
(unsigned long)atomic_inc_return(&gameport_no) - 1);
|
||||||
gameport->dev.bus = &gameport_bus;
|
gameport->dev.bus = &gameport_bus;
|
||||||
gameport->dev.release = gameport_release_port;
|
gameport->dev.release = gameport_release_port;
|
||||||
if (gameport->parent)
|
if (gameport->parent)
|
||||||
|
|
@ -550,19 +538,17 @@ static void gameport_add_port(struct gameport *gameport)
|
||||||
list_add_tail(&gameport->node, &gameport_list);
|
list_add_tail(&gameport->node, &gameport_list);
|
||||||
|
|
||||||
if (gameport->io)
|
if (gameport->io)
|
||||||
printk(KERN_INFO "gameport: %s is %s, io %#x, speed %dkHz\n",
|
dev_info(&gameport->dev, "%s is %s, io %#x, speed %dkHz\n",
|
||||||
gameport->name, gameport->phys, gameport->io, gameport->speed);
|
gameport->name, gameport->phys, gameport->io, gameport->speed);
|
||||||
else
|
else
|
||||||
printk(KERN_INFO "gameport: %s is %s, speed %dkHz\n",
|
dev_info(&gameport->dev, "%s is %s, speed %dkHz\n",
|
||||||
gameport->name, gameport->phys, gameport->speed);
|
gameport->name, gameport->phys, gameport->speed);
|
||||||
|
|
||||||
error = device_add(&gameport->dev);
|
error = device_add(&gameport->dev);
|
||||||
if (error)
|
if (error)
|
||||||
printk(KERN_ERR
|
dev_err(&gameport->dev,
|
||||||
"gameport: device_add() failed for %s (%s), error: %d\n",
|
"device_add() failed for %s (%s), error: %d\n",
|
||||||
gameport->phys, gameport->name, error);
|
gameport->phys, gameport->name, error);
|
||||||
else
|
|
||||||
gameport->registered = 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -584,10 +570,8 @@ static void gameport_destroy_port(struct gameport *gameport)
|
||||||
gameport->parent = NULL;
|
gameport->parent = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gameport->registered) {
|
if (device_is_registered(&gameport->dev))
|
||||||
device_del(&gameport->dev);
|
device_del(&gameport->dev);
|
||||||
gameport->registered = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
list_del_init(&gameport->node);
|
list_del_init(&gameport->node);
|
||||||
|
|
||||||
|
|
@ -705,8 +689,7 @@ static void gameport_attach_driver(struct gameport_driver *drv)
|
||||||
|
|
||||||
error = driver_attach(&drv->driver);
|
error = driver_attach(&drv->driver);
|
||||||
if (error)
|
if (error)
|
||||||
printk(KERN_ERR
|
pr_err("driver_attach() failed for %s, error: %d\n",
|
||||||
"gameport: driver_attach() failed for %s, error: %d\n",
|
|
||||||
drv->driver.name, error);
|
drv->driver.name, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -727,8 +710,7 @@ int __gameport_register_driver(struct gameport_driver *drv, struct module *owner
|
||||||
|
|
||||||
error = driver_register(&drv->driver);
|
error = driver_register(&drv->driver);
|
||||||
if (error) {
|
if (error) {
|
||||||
printk(KERN_ERR
|
pr_err("driver_register() failed for %s, error: %d\n",
|
||||||
"gameport: driver_register() failed for %s, error: %d\n",
|
|
||||||
drv->driver.name, error);
|
drv->driver.name, error);
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
@ -828,7 +810,7 @@ static int __init gameport_init(void)
|
||||||
|
|
||||||
error = bus_register(&gameport_bus);
|
error = bus_register(&gameport_bus);
|
||||||
if (error) {
|
if (error) {
|
||||||
printk(KERN_ERR "gameport: failed to register gameport bus, error: %d\n", error);
|
pr_err("failed to register gameport bus, error: %d\n", error);
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -836,7 +818,7 @@ static int __init gameport_init(void)
|
||||||
if (IS_ERR(gameport_task)) {
|
if (IS_ERR(gameport_task)) {
|
||||||
bus_unregister(&gameport_bus);
|
bus_unregister(&gameport_bus);
|
||||||
error = PTR_ERR(gameport_task);
|
error = PTR_ERR(gameport_task);
|
||||||
printk(KERN_ERR "gameport: Failed to start kgameportd, error: %d\n", error);
|
pr_err("Failed to start kgameportd, error: %d\n", error);
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -166,7 +166,7 @@ static int ns558_isa_probe(int io)
|
||||||
|
|
||||||
#ifdef CONFIG_PNP
|
#ifdef CONFIG_PNP
|
||||||
|
|
||||||
static struct pnp_device_id pnp_devids[] = {
|
static const struct pnp_device_id pnp_devids[] = {
|
||||||
{ .id = "@P@0001", .driver_data = 0 }, /* ALS 100 */
|
{ .id = "@P@0001", .driver_data = 0 }, /* ALS 100 */
|
||||||
{ .id = "@P@0020", .driver_data = 0 }, /* ALS 200 */
|
{ .id = "@P@0020", .driver_data = 0 }, /* ALS 200 */
|
||||||
{ .id = "@P@1001", .driver_data = 0 }, /* ALS 100+ */
|
{ .id = "@P@1001", .driver_data = 0 }, /* ALS 100+ */
|
||||||
|
|
|
||||||
|
|
@ -87,12 +87,14 @@ static int input_defuzz_abs_event(int value, int old_val, int fuzz)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Pass event through all open handles. This function is called with
|
* Pass event first through all filters and then, if event has not been
|
||||||
|
* filtered out, through all open handles. This function is called with
|
||||||
* dev->event_lock held and interrupts disabled.
|
* dev->event_lock held and interrupts disabled.
|
||||||
*/
|
*/
|
||||||
static void input_pass_event(struct input_dev *dev,
|
static void input_pass_event(struct input_dev *dev,
|
||||||
unsigned int type, unsigned int code, int value)
|
unsigned int type, unsigned int code, int value)
|
||||||
{
|
{
|
||||||
|
struct input_handler *handler;
|
||||||
struct input_handle *handle;
|
struct input_handle *handle;
|
||||||
|
|
||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
|
|
@ -100,11 +102,25 @@ static void input_pass_event(struct input_dev *dev,
|
||||||
handle = rcu_dereference(dev->grab);
|
handle = rcu_dereference(dev->grab);
|
||||||
if (handle)
|
if (handle)
|
||||||
handle->handler->event(handle, type, code, value);
|
handle->handler->event(handle, type, code, value);
|
||||||
else
|
else {
|
||||||
list_for_each_entry_rcu(handle, &dev->h_list, d_node)
|
bool filtered = false;
|
||||||
if (handle->open)
|
|
||||||
handle->handler->event(handle,
|
list_for_each_entry_rcu(handle, &dev->h_list, d_node) {
|
||||||
type, code, value);
|
if (!handle->open)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
handler = handle->handler;
|
||||||
|
if (!handler->filter) {
|
||||||
|
if (filtered)
|
||||||
|
break;
|
||||||
|
|
||||||
|
handler->event(handle, type, code, value);
|
||||||
|
|
||||||
|
} else if (handler->filter(handle, type, code, value))
|
||||||
|
filtered = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -615,12 +631,12 @@ static int input_default_setkeycode(struct input_dev *dev,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
clear_bit(old_keycode, dev->keybit);
|
__clear_bit(old_keycode, dev->keybit);
|
||||||
set_bit(keycode, dev->keybit);
|
__set_bit(keycode, dev->keybit);
|
||||||
|
|
||||||
for (i = 0; i < dev->keycodemax; i++) {
|
for (i = 0; i < dev->keycodemax; i++) {
|
||||||
if (input_fetch_keycode(dev, i) == old_keycode) {
|
if (input_fetch_keycode(dev, i) == old_keycode) {
|
||||||
set_bit(old_keycode, dev->keybit);
|
__set_bit(old_keycode, dev->keybit);
|
||||||
break; /* Setting the bit twice is useless, so break */
|
break; /* Setting the bit twice is useless, so break */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -678,6 +694,9 @@ int input_set_keycode(struct input_dev *dev, int scancode, int keycode)
|
||||||
if (retval)
|
if (retval)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
/* Make sure KEY_RESERVED did not get enabled. */
|
||||||
|
__clear_bit(KEY_RESERVED, dev->keybit);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Simulate keyup event if keycode is not present
|
* Simulate keyup event if keycode is not present
|
||||||
* in the keymap anymore
|
* in the keymap anymore
|
||||||
|
|
@ -705,12 +724,13 @@ EXPORT_SYMBOL(input_set_keycode);
|
||||||
if (i != BITS_TO_LONGS(max)) \
|
if (i != BITS_TO_LONGS(max)) \
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
static const struct input_device_id *input_match_device(const struct input_device_id *id,
|
static const struct input_device_id *input_match_device(struct input_handler *handler,
|
||||||
struct input_dev *dev)
|
struct input_dev *dev)
|
||||||
{
|
{
|
||||||
|
const struct input_device_id *id;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (; id->flags || id->driver_info; id++) {
|
for (id = handler->id_table; id->flags || id->driver_info; id++) {
|
||||||
|
|
||||||
if (id->flags & INPUT_DEVICE_ID_MATCH_BUS)
|
if (id->flags & INPUT_DEVICE_ID_MATCH_BUS)
|
||||||
if (id->bustype != dev->id.bustype)
|
if (id->bustype != dev->id.bustype)
|
||||||
|
|
@ -738,6 +758,7 @@ static const struct input_device_id *input_match_device(const struct input_devic
|
||||||
MATCH_BIT(ffbit, FF_MAX);
|
MATCH_BIT(ffbit, FF_MAX);
|
||||||
MATCH_BIT(swbit, SW_MAX);
|
MATCH_BIT(swbit, SW_MAX);
|
||||||
|
|
||||||
|
if (!handler->match || handler->match(handler, dev))
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -749,10 +770,7 @@ static int input_attach_handler(struct input_dev *dev, struct input_handler *han
|
||||||
const struct input_device_id *id;
|
const struct input_device_id *id;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
if (handler->blacklist && input_match_device(handler->blacklist, dev))
|
id = input_match_device(handler, dev);
|
||||||
return -ENODEV;
|
|
||||||
|
|
||||||
id = input_match_device(handler->id_table, dev);
|
|
||||||
if (!id)
|
if (!id)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
|
|
@ -988,6 +1006,8 @@ static int input_handlers_seq_show(struct seq_file *seq, void *v)
|
||||||
union input_seq_state *state = (union input_seq_state *)&seq->private;
|
union input_seq_state *state = (union input_seq_state *)&seq->private;
|
||||||
|
|
||||||
seq_printf(seq, "N: Number=%u Name=%s", state->pos, handler->name);
|
seq_printf(seq, "N: Number=%u Name=%s", state->pos, handler->name);
|
||||||
|
if (handler->filter)
|
||||||
|
seq_puts(seq, " (filter)");
|
||||||
if (handler->fops)
|
if (handler->fops)
|
||||||
seq_printf(seq, " Minor=%d", handler->minor);
|
seq_printf(seq, " Minor=%d", handler->minor);
|
||||||
seq_putc(seq, '\n');
|
seq_putc(seq, '\n');
|
||||||
|
|
@ -1551,6 +1571,25 @@ void input_set_capability(struct input_dev *dev, unsigned int type, unsigned int
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(input_set_capability);
|
EXPORT_SYMBOL(input_set_capability);
|
||||||
|
|
||||||
|
#define INPUT_CLEANSE_BITMASK(dev, type, bits) \
|
||||||
|
do { \
|
||||||
|
if (!test_bit(EV_##type, dev->evbit)) \
|
||||||
|
memset(dev->bits##bit, 0, \
|
||||||
|
sizeof(dev->bits##bit)); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
static void input_cleanse_bitmasks(struct input_dev *dev)
|
||||||
|
{
|
||||||
|
INPUT_CLEANSE_BITMASK(dev, KEY, key);
|
||||||
|
INPUT_CLEANSE_BITMASK(dev, REL, rel);
|
||||||
|
INPUT_CLEANSE_BITMASK(dev, ABS, abs);
|
||||||
|
INPUT_CLEANSE_BITMASK(dev, MSC, msc);
|
||||||
|
INPUT_CLEANSE_BITMASK(dev, LED, led);
|
||||||
|
INPUT_CLEANSE_BITMASK(dev, SND, snd);
|
||||||
|
INPUT_CLEANSE_BITMASK(dev, FF, ff);
|
||||||
|
INPUT_CLEANSE_BITMASK(dev, SW, sw);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* input_register_device - register device with input core
|
* input_register_device - register device with input core
|
||||||
* @dev: device to be registered
|
* @dev: device to be registered
|
||||||
|
|
@ -1570,13 +1609,19 @@ int input_register_device(struct input_dev *dev)
|
||||||
const char *path;
|
const char *path;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
|
/* Every input device generates EV_SYN/SYN_REPORT events. */
|
||||||
__set_bit(EV_SYN, dev->evbit);
|
__set_bit(EV_SYN, dev->evbit);
|
||||||
|
|
||||||
|
/* KEY_RESERVED is not supposed to be transmitted to userspace. */
|
||||||
|
__clear_bit(KEY_RESERVED, dev->keybit);
|
||||||
|
|
||||||
|
/* Make sure that bitmasks not mentioned in dev->evbit are clean. */
|
||||||
|
input_cleanse_bitmasks(dev);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If delay and period are pre-set by the driver, then autorepeating
|
* If delay and period are pre-set by the driver, then autorepeating
|
||||||
* is handled by the driver itself and we don't do it in input.c.
|
* is handled by the driver itself and we don't do it in input.c.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
init_timer(&dev->timer);
|
init_timer(&dev->timer);
|
||||||
if (!dev->rep[REP_DELAY] && !dev->rep[REP_PERIOD]) {
|
if (!dev->rep[REP_DELAY] && !dev->rep[REP_PERIOD]) {
|
||||||
dev->timer.data = (long) dev;
|
dev->timer.data = (long) dev;
|
||||||
|
|
@ -1776,7 +1821,16 @@ int input_register_handle(struct input_handle *handle)
|
||||||
error = mutex_lock_interruptible(&dev->mutex);
|
error = mutex_lock_interruptible(&dev->mutex);
|
||||||
if (error)
|
if (error)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Filters go to the head of the list, normal handlers
|
||||||
|
* to the tail.
|
||||||
|
*/
|
||||||
|
if (handler->filter)
|
||||||
|
list_add_rcu(&handle->d_node, &dev->h_list);
|
||||||
|
else
|
||||||
list_add_tail_rcu(&handle->d_node, &dev->h_list);
|
list_add_tail_rcu(&handle->d_node, &dev->h_list);
|
||||||
|
|
||||||
mutex_unlock(&dev->mutex);
|
mutex_unlock(&dev->mutex);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
|
|
@ -286,6 +286,8 @@ static int joydev_open(struct inode *inode, struct file *file)
|
||||||
goto err_free_client;
|
goto err_free_client;
|
||||||
|
|
||||||
file->private_data = client;
|
file->private_data = client;
|
||||||
|
nonseekable_open(inode, file);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err_free_client:
|
err_free_client:
|
||||||
|
|
@ -775,6 +777,20 @@ static void joydev_cleanup(struct joydev *joydev)
|
||||||
input_close_device(handle);
|
input_close_device(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static bool joydev_match(struct input_handler *handler, struct input_dev *dev)
|
||||||
|
{
|
||||||
|
/* Avoid touchpads and touchscreens */
|
||||||
|
if (test_bit(EV_KEY, dev->evbit) && test_bit(BTN_TOUCH, dev->keybit))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* Avoid tablets, digitisers and similar devices */
|
||||||
|
if (test_bit(EV_KEY, dev->evbit) && test_bit(BTN_DIGI, dev->keybit))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static int joydev_connect(struct input_handler *handler, struct input_dev *dev,
|
static int joydev_connect(struct input_handler *handler, struct input_dev *dev,
|
||||||
const struct input_device_id *id)
|
const struct input_device_id *id)
|
||||||
{
|
{
|
||||||
|
|
@ -894,22 +910,6 @@ static void joydev_disconnect(struct input_handle *handle)
|
||||||
put_device(&joydev->dev);
|
put_device(&joydev->dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct input_device_id joydev_blacklist[] = {
|
|
||||||
{
|
|
||||||
.flags = INPUT_DEVICE_ID_MATCH_EVBIT |
|
|
||||||
INPUT_DEVICE_ID_MATCH_KEYBIT,
|
|
||||||
.evbit = { BIT_MASK(EV_KEY) },
|
|
||||||
.keybit = { [BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH) },
|
|
||||||
}, /* Avoid itouchpads and touchscreens */
|
|
||||||
{
|
|
||||||
.flags = INPUT_DEVICE_ID_MATCH_EVBIT |
|
|
||||||
INPUT_DEVICE_ID_MATCH_KEYBIT,
|
|
||||||
.evbit = { BIT_MASK(EV_KEY) },
|
|
||||||
.keybit = { [BIT_WORD(BTN_DIGI)] = BIT_MASK(BTN_DIGI) },
|
|
||||||
}, /* Avoid tablets, digitisers and similar devices */
|
|
||||||
{ } /* Terminating entry */
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct input_device_id joydev_ids[] = {
|
static const struct input_device_id joydev_ids[] = {
|
||||||
{
|
{
|
||||||
.flags = INPUT_DEVICE_ID_MATCH_EVBIT |
|
.flags = INPUT_DEVICE_ID_MATCH_EVBIT |
|
||||||
|
|
@ -936,13 +936,13 @@ MODULE_DEVICE_TABLE(input, joydev_ids);
|
||||||
|
|
||||||
static struct input_handler joydev_handler = {
|
static struct input_handler joydev_handler = {
|
||||||
.event = joydev_event,
|
.event = joydev_event,
|
||||||
|
.match = joydev_match,
|
||||||
.connect = joydev_connect,
|
.connect = joydev_connect,
|
||||||
.disconnect = joydev_disconnect,
|
.disconnect = joydev_disconnect,
|
||||||
.fops = &joydev_fops,
|
.fops = &joydev_fops,
|
||||||
.minor = JOYDEV_MINOR_BASE,
|
.minor = JOYDEV_MINOR_BASE,
|
||||||
.name = "joydev",
|
.name = "joydev",
|
||||||
.id_table = joydev_ids,
|
.id_table = joydev_ids,
|
||||||
.blacklist = joydev_blacklist,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static int __init joydev_init(void)
|
static int __init joydev_init(void)
|
||||||
|
|
|
||||||
|
|
@ -221,6 +221,7 @@ config JOYSTICK_DB9
|
||||||
config JOYSTICK_GAMECON
|
config JOYSTICK_GAMECON
|
||||||
tristate "Multisystem, NES, SNES, N64, PSX joysticks and gamepads"
|
tristate "Multisystem, NES, SNES, N64, PSX joysticks and gamepads"
|
||||||
depends on PARPORT
|
depends on PARPORT
|
||||||
|
select INPUT_FF_MEMLESS
|
||||||
---help---
|
---help---
|
||||||
Say Y here if you have a Nintendo Entertainment System gamepad,
|
Say Y here if you have a Nintendo Entertainment System gamepad,
|
||||||
Super Nintendo Entertainment System gamepad, Nintendo 64 gamepad,
|
Super Nintendo Entertainment System gamepad, Nintendo 64 gamepad,
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,8 @@
|
||||||
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
|
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||||
|
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
|
|
@ -61,48 +63,73 @@ MODULE_PARM_DESC(map3, "Describes third set of devices");
|
||||||
|
|
||||||
/* see also gs_psx_delay parameter in PSX support section */
|
/* see also gs_psx_delay parameter in PSX support section */
|
||||||
|
|
||||||
#define GC_SNES 1
|
enum gc_type {
|
||||||
#define GC_NES 2
|
GC_NONE = 0,
|
||||||
#define GC_NES4 3
|
GC_SNES,
|
||||||
#define GC_MULTI 4
|
GC_NES,
|
||||||
#define GC_MULTI2 5
|
GC_NES4,
|
||||||
#define GC_N64 6
|
GC_MULTI,
|
||||||
#define GC_PSX 7
|
GC_MULTI2,
|
||||||
#define GC_DDR 8
|
GC_N64,
|
||||||
#define GC_SNESMOUSE 9
|
GC_PSX,
|
||||||
|
GC_DDR,
|
||||||
#define GC_MAX 9
|
GC_SNESMOUSE,
|
||||||
|
GC_MAX
|
||||||
|
};
|
||||||
|
|
||||||
#define GC_REFRESH_TIME HZ/100
|
#define GC_REFRESH_TIME HZ/100
|
||||||
|
|
||||||
|
struct gc_pad {
|
||||||
|
struct input_dev *dev;
|
||||||
|
enum gc_type type;
|
||||||
|
char phys[32];
|
||||||
|
};
|
||||||
|
|
||||||
struct gc {
|
struct gc {
|
||||||
struct pardevice *pd;
|
struct pardevice *pd;
|
||||||
|
struct gc_pad pads[GC_MAX_DEVICES];
|
||||||
struct input_dev *dev[GC_MAX_DEVICES];
|
struct input_dev *dev[GC_MAX_DEVICES];
|
||||||
struct timer_list timer;
|
struct timer_list timer;
|
||||||
unsigned char pads[GC_MAX + 1];
|
int pad_count[GC_MAX];
|
||||||
int used;
|
int used;
|
||||||
struct mutex mutex;
|
struct mutex mutex;
|
||||||
char phys[GC_MAX_DEVICES][32];
|
};
|
||||||
|
|
||||||
|
struct gc_subdev {
|
||||||
|
unsigned int idx;
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct gc *gc_base[3];
|
static struct gc *gc_base[3];
|
||||||
|
|
||||||
static int gc_status_bit[] = { 0x40, 0x80, 0x20, 0x10, 0x08 };
|
static const int gc_status_bit[] = { 0x40, 0x80, 0x20, 0x10, 0x08 };
|
||||||
|
|
||||||
static char *gc_names[] = { NULL, "SNES pad", "NES pad", "NES FourPort", "Multisystem joystick",
|
static const char *gc_names[] = {
|
||||||
|
NULL, "SNES pad", "NES pad", "NES FourPort", "Multisystem joystick",
|
||||||
"Multisystem 2-button joystick", "N64 controller", "PSX controller",
|
"Multisystem 2-button joystick", "N64 controller", "PSX controller",
|
||||||
"PSX DDR controller", "SNES mouse" };
|
"PSX DDR controller", "SNES mouse"
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* N64 support.
|
* N64 support.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static unsigned char gc_n64_bytes[] = { 0, 1, 13, 15, 14, 12, 10, 11, 2, 3 };
|
static const unsigned char gc_n64_bytes[] = { 0, 1, 13, 15, 14, 12, 10, 11, 2, 3 };
|
||||||
static short gc_n64_btn[] = { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_TRIGGER, BTN_START };
|
static const short gc_n64_btn[] = {
|
||||||
|
BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z,
|
||||||
|
BTN_TL, BTN_TR, BTN_TRIGGER, BTN_START
|
||||||
|
};
|
||||||
|
|
||||||
#define GC_N64_LENGTH 32 /* N64 bit length, not including stop bit */
|
#define GC_N64_LENGTH 32 /* N64 bit length, not including stop bit */
|
||||||
#define GC_N64_REQUEST_LENGTH 37 /* transmit request sequence is 9 bits long */
|
#define GC_N64_STOP_LENGTH 5 /* Length of encoded stop bit */
|
||||||
|
#define GC_N64_CMD_00 0x11111111UL
|
||||||
|
#define GC_N64_CMD_01 0xd1111111UL
|
||||||
|
#define GC_N64_CMD_03 0xdd111111UL
|
||||||
|
#define GC_N64_CMD_1b 0xdd1dd111UL
|
||||||
|
#define GC_N64_CMD_c0 0x111111ddUL
|
||||||
|
#define GC_N64_CMD_80 0x1111111dUL
|
||||||
|
#define GC_N64_STOP_BIT 0x1d /* Encoded stop bit */
|
||||||
|
#define GC_N64_REQUEST_DATA GC_N64_CMD_01 /* the request data command */
|
||||||
#define GC_N64_DELAY 133 /* delay between transmit request, and response ready (us) */
|
#define GC_N64_DELAY 133 /* delay between transmit request, and response ready (us) */
|
||||||
#define GC_N64_REQUEST 0x1dd1111111ULL /* the request data command (encoded for 000000011) */
|
|
||||||
#define GC_N64_DWS 3 /* delay between write segments (required for sound playback because of ISA DMA) */
|
#define GC_N64_DWS 3 /* delay between write segments (required for sound playback because of ISA DMA) */
|
||||||
/* GC_N64_DWS > 24 is known to fail */
|
/* GC_N64_DWS > 24 is known to fail */
|
||||||
#define GC_N64_POWER_W 0xe2 /* power during write (transmit request) */
|
#define GC_N64_POWER_W 0xe2 /* power during write (transmit request) */
|
||||||
|
|
@ -113,9 +140,41 @@ static short gc_n64_btn[] = { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL,
|
||||||
/* than 123 us */
|
/* than 123 us */
|
||||||
#define GC_N64_CLOCK 0x02 /* clock bits for read */
|
#define GC_N64_CLOCK 0x02 /* clock bits for read */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Used for rumble code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Send encoded command */
|
||||||
|
static void gc_n64_send_command(struct gc *gc, unsigned long cmd,
|
||||||
|
unsigned char target)
|
||||||
|
{
|
||||||
|
struct parport *port = gc->pd->port;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < GC_N64_LENGTH; i++) {
|
||||||
|
unsigned char data = (cmd >> i) & 1 ? target : 0;
|
||||||
|
parport_write_data(port, GC_N64_POWER_W | data);
|
||||||
|
udelay(GC_N64_DWS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Send stop bit */
|
||||||
|
static void gc_n64_send_stop_bit(struct gc *gc, unsigned char target)
|
||||||
|
{
|
||||||
|
struct parport *port = gc->pd->port;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < GC_N64_STOP_LENGTH; i++) {
|
||||||
|
unsigned char data = (GC_N64_STOP_BIT >> i) & 1 ? target : 0;
|
||||||
|
parport_write_data(port, GC_N64_POWER_W | data);
|
||||||
|
udelay(GC_N64_DWS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* gc_n64_read_packet() reads an N64 packet.
|
* gc_n64_read_packet() reads an N64 packet.
|
||||||
* Each pad uses one bit per byte. So all pads connected to this port are read in parallel.
|
* Each pad uses one bit per byte. So all pads connected to this port
|
||||||
|
* are read in parallel.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static void gc_n64_read_packet(struct gc *gc, unsigned char *data)
|
static void gc_n64_read_packet(struct gc *gc, unsigned char *data)
|
||||||
|
|
@ -128,14 +187,13 @@ static void gc_n64_read_packet(struct gc *gc, unsigned char *data)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
local_irq_save(flags);
|
local_irq_save(flags);
|
||||||
for (i = 0; i < GC_N64_REQUEST_LENGTH; i++) {
|
gc_n64_send_command(gc, GC_N64_REQUEST_DATA, GC_N64_OUT);
|
||||||
parport_write_data(gc->pd->port, GC_N64_POWER_W | ((GC_N64_REQUEST >> i) & 1 ? GC_N64_OUT : 0));
|
gc_n64_send_stop_bit(gc, GC_N64_OUT);
|
||||||
udelay(GC_N64_DWS);
|
|
||||||
}
|
|
||||||
local_irq_restore(flags);
|
local_irq_restore(flags);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Wait for the pad response to be loaded into the 33-bit register of the adapter
|
* Wait for the pad response to be loaded into the 33-bit register
|
||||||
|
* of the adapter.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
udelay(GC_N64_DELAY);
|
udelay(GC_N64_DELAY);
|
||||||
|
|
@ -146,13 +204,15 @@ static void gc_n64_read_packet(struct gc *gc, unsigned char *data)
|
||||||
|
|
||||||
for (i = 0; i < GC_N64_LENGTH; i++) {
|
for (i = 0; i < GC_N64_LENGTH; i++) {
|
||||||
parport_write_data(gc->pd->port, GC_N64_POWER_R);
|
parport_write_data(gc->pd->port, GC_N64_POWER_R);
|
||||||
|
udelay(2);
|
||||||
data[i] = parport_read_status(gc->pd->port);
|
data[i] = parport_read_status(gc->pd->port);
|
||||||
parport_write_data(gc->pd->port, GC_N64_POWER_R | GC_N64_CLOCK);
|
parport_write_data(gc->pd->port, GC_N64_POWER_R | GC_N64_CLOCK);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We must wait 200 ms here for the controller to reinitialize before the next read request.
|
* We must wait 200 ms here for the controller to reinitialize before
|
||||||
* No worries as long as gc_read is polled less frequently than this.
|
* the next read request. No worries as long as gc_read is polled less
|
||||||
|
* frequently than this.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -160,45 +220,112 @@ static void gc_n64_read_packet(struct gc *gc, unsigned char *data)
|
||||||
static void gc_n64_process_packet(struct gc *gc)
|
static void gc_n64_process_packet(struct gc *gc)
|
||||||
{
|
{
|
||||||
unsigned char data[GC_N64_LENGTH];
|
unsigned char data[GC_N64_LENGTH];
|
||||||
signed char axes[2];
|
|
||||||
struct input_dev *dev;
|
struct input_dev *dev;
|
||||||
int i, j, s;
|
int i, j, s;
|
||||||
|
signed char x, y;
|
||||||
|
|
||||||
gc_n64_read_packet(gc, data);
|
gc_n64_read_packet(gc, data);
|
||||||
|
|
||||||
for (i = 0; i < GC_MAX_DEVICES; i++) {
|
for (i = 0; i < GC_MAX_DEVICES; i++) {
|
||||||
|
|
||||||
dev = gc->dev[i];
|
if (gc->pads[i].type != GC_N64)
|
||||||
if (!dev)
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
dev = gc->pads[i].dev;
|
||||||
s = gc_status_bit[i];
|
s = gc_status_bit[i];
|
||||||
|
|
||||||
if (s & gc->pads[GC_N64] & ~(data[8] | data[9])) {
|
if (s & ~(data[8] | data[9])) {
|
||||||
|
|
||||||
axes[0] = axes[1] = 0;
|
x = y = 0;
|
||||||
|
|
||||||
for (j = 0; j < 8; j++) {
|
for (j = 0; j < 8; j++) {
|
||||||
if (data[23 - j] & s)
|
if (data[23 - j] & s)
|
||||||
axes[0] |= 1 << j;
|
x |= 1 << j;
|
||||||
if (data[31 - j] & s)
|
if (data[31 - j] & s)
|
||||||
axes[1] |= 1 << j;
|
y |= 1 << j;
|
||||||
}
|
}
|
||||||
|
|
||||||
input_report_abs(dev, ABS_X, axes[0]);
|
input_report_abs(dev, ABS_X, x);
|
||||||
input_report_abs(dev, ABS_Y, -axes[1]);
|
input_report_abs(dev, ABS_Y, -y);
|
||||||
|
|
||||||
input_report_abs(dev, ABS_HAT0X, !(s & data[6]) - !(s & data[7]));
|
input_report_abs(dev, ABS_HAT0X,
|
||||||
input_report_abs(dev, ABS_HAT0Y, !(s & data[4]) - !(s & data[5]));
|
!(s & data[6]) - !(s & data[7]));
|
||||||
|
input_report_abs(dev, ABS_HAT0Y,
|
||||||
|
!(s & data[4]) - !(s & data[5]));
|
||||||
|
|
||||||
for (j = 0; j < 10; j++)
|
for (j = 0; j < 10; j++)
|
||||||
input_report_key(dev, gc_n64_btn[j], s & data[gc_n64_bytes[j]]);
|
input_report_key(dev, gc_n64_btn[j],
|
||||||
|
s & data[gc_n64_bytes[j]]);
|
||||||
|
|
||||||
input_sync(dev);
|
input_sync(dev);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int gc_n64_play_effect(struct input_dev *dev, void *data,
|
||||||
|
struct ff_effect *effect)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
unsigned long flags;
|
||||||
|
struct gc *gc = input_get_drvdata(dev);
|
||||||
|
struct gc_subdev *sdev = data;
|
||||||
|
unsigned char target = 1 << sdev->idx; /* select desired pin */
|
||||||
|
|
||||||
|
if (effect->type == FF_RUMBLE) {
|
||||||
|
struct ff_rumble_effect *rumble = &effect->u.rumble;
|
||||||
|
unsigned int cmd =
|
||||||
|
rumble->strong_magnitude || rumble->weak_magnitude ?
|
||||||
|
GC_N64_CMD_01 : GC_N64_CMD_00;
|
||||||
|
|
||||||
|
local_irq_save(flags);
|
||||||
|
|
||||||
|
/* Init Rumble - 0x03, 0x80, 0x01, (34)0x80 */
|
||||||
|
gc_n64_send_command(gc, GC_N64_CMD_03, target);
|
||||||
|
gc_n64_send_command(gc, GC_N64_CMD_80, target);
|
||||||
|
gc_n64_send_command(gc, GC_N64_CMD_01, target);
|
||||||
|
for (i = 0; i < 32; i++)
|
||||||
|
gc_n64_send_command(gc, GC_N64_CMD_80, target);
|
||||||
|
gc_n64_send_stop_bit(gc, target);
|
||||||
|
|
||||||
|
udelay(GC_N64_DELAY);
|
||||||
|
|
||||||
|
/* Now start or stop it - 0x03, 0xc0, 0zx1b, (32)0x01/0x00 */
|
||||||
|
gc_n64_send_command(gc, GC_N64_CMD_03, target);
|
||||||
|
gc_n64_send_command(gc, GC_N64_CMD_c0, target);
|
||||||
|
gc_n64_send_command(gc, GC_N64_CMD_1b, target);
|
||||||
|
for (i = 0; i < 32; i++)
|
||||||
|
gc_n64_send_command(gc, cmd, target);
|
||||||
|
gc_n64_send_stop_bit(gc, target);
|
||||||
|
|
||||||
|
local_irq_restore(flags);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __init gc_n64_init_ff(struct input_dev *dev, int i)
|
||||||
|
{
|
||||||
|
struct gc_subdev *sdev;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
sdev = kmalloc(sizeof(*sdev), GFP_KERNEL);
|
||||||
|
if (!sdev)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
sdev->idx = i;
|
||||||
|
|
||||||
|
input_set_capability(dev, EV_FF, FF_RUMBLE);
|
||||||
|
|
||||||
|
err = input_ff_create_memless(dev, sdev, gc_n64_play_effect);
|
||||||
|
if (err) {
|
||||||
|
kfree(sdev);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* NES/SNES support.
|
* NES/SNES support.
|
||||||
*/
|
*/
|
||||||
|
|
@ -214,9 +341,11 @@ static void gc_n64_process_packet(struct gc *gc)
|
||||||
#define GC_NES_CLOCK 0x01
|
#define GC_NES_CLOCK 0x01
|
||||||
#define GC_NES_LATCH 0x02
|
#define GC_NES_LATCH 0x02
|
||||||
|
|
||||||
static unsigned char gc_nes_bytes[] = { 0, 1, 2, 3 };
|
static const unsigned char gc_nes_bytes[] = { 0, 1, 2, 3 };
|
||||||
static unsigned char gc_snes_bytes[] = { 8, 0, 2, 3, 9, 1, 10, 11 };
|
static const unsigned char gc_snes_bytes[] = { 8, 0, 2, 3, 9, 1, 10, 11 };
|
||||||
static short gc_snes_btn[] = { BTN_A, BTN_B, BTN_SELECT, BTN_START, BTN_X, BTN_Y, BTN_TL, BTN_TR };
|
static const short gc_snes_btn[] = {
|
||||||
|
BTN_A, BTN_B, BTN_SELECT, BTN_START, BTN_X, BTN_Y, BTN_TL, BTN_TR
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* gc_nes_read_packet() reads a NES/SNES packet.
|
* gc_nes_read_packet() reads a NES/SNES packet.
|
||||||
|
|
@ -244,40 +373,51 @@ static void gc_nes_read_packet(struct gc *gc, int length, unsigned char *data)
|
||||||
static void gc_nes_process_packet(struct gc *gc)
|
static void gc_nes_process_packet(struct gc *gc)
|
||||||
{
|
{
|
||||||
unsigned char data[GC_SNESMOUSE_LENGTH];
|
unsigned char data[GC_SNESMOUSE_LENGTH];
|
||||||
|
struct gc_pad *pad;
|
||||||
struct input_dev *dev;
|
struct input_dev *dev;
|
||||||
int i, j, s, len;
|
int i, j, s, len;
|
||||||
char x_rel, y_rel;
|
char x_rel, y_rel;
|
||||||
|
|
||||||
len = gc->pads[GC_SNESMOUSE] ? GC_SNESMOUSE_LENGTH :
|
len = gc->pad_count[GC_SNESMOUSE] ? GC_SNESMOUSE_LENGTH :
|
||||||
(gc->pads[GC_SNES] ? GC_SNES_LENGTH : GC_NES_LENGTH);
|
(gc->pad_count[GC_SNES] ? GC_SNES_LENGTH : GC_NES_LENGTH);
|
||||||
|
|
||||||
gc_nes_read_packet(gc, len, data);
|
gc_nes_read_packet(gc, len, data);
|
||||||
|
|
||||||
for (i = 0; i < GC_MAX_DEVICES; i++) {
|
for (i = 0; i < GC_MAX_DEVICES; i++) {
|
||||||
|
|
||||||
|
pad = &gc->pads[i];
|
||||||
dev = gc->dev[i];
|
dev = gc->dev[i];
|
||||||
if (!dev)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
s = gc_status_bit[i];
|
s = gc_status_bit[i];
|
||||||
|
|
||||||
if (s & (gc->pads[GC_NES] | gc->pads[GC_SNES])) {
|
switch (pad->type) {
|
||||||
|
|
||||||
|
case GC_NES:
|
||||||
|
|
||||||
input_report_abs(dev, ABS_X, !(s & data[6]) - !(s & data[7]));
|
input_report_abs(dev, ABS_X, !(s & data[6]) - !(s & data[7]));
|
||||||
input_report_abs(dev, ABS_Y, !(s & data[4]) - !(s & data[5]));
|
input_report_abs(dev, ABS_Y, !(s & data[4]) - !(s & data[5]));
|
||||||
}
|
|
||||||
|
|
||||||
if (s & gc->pads[GC_NES])
|
|
||||||
for (j = 0; j < 4; j++)
|
for (j = 0; j < 4; j++)
|
||||||
input_report_key(dev, gc_snes_btn[j], s & data[gc_nes_bytes[j]]);
|
input_report_key(dev, gc_snes_btn[j],
|
||||||
|
s & data[gc_nes_bytes[j]]);
|
||||||
|
input_sync(dev);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GC_SNES:
|
||||||
|
|
||||||
|
input_report_abs(dev, ABS_X, !(s & data[6]) - !(s & data[7]));
|
||||||
|
input_report_abs(dev, ABS_Y, !(s & data[4]) - !(s & data[5]));
|
||||||
|
|
||||||
if (s & gc->pads[GC_SNES])
|
|
||||||
for (j = 0; j < 8; j++)
|
for (j = 0; j < 8; j++)
|
||||||
input_report_key(dev, gc_snes_btn[j], s & data[gc_snes_bytes[j]]);
|
input_report_key(dev, gc_snes_btn[j],
|
||||||
|
s & data[gc_snes_bytes[j]]);
|
||||||
|
input_sync(dev);
|
||||||
|
break;
|
||||||
|
|
||||||
if (s & gc->pads[GC_SNESMOUSE]) {
|
case GC_SNESMOUSE:
|
||||||
/*
|
/*
|
||||||
* The 4 unused bits from SNES controllers appear to be ID bits
|
* The 4 unused bits from SNES controllers appear
|
||||||
* so use them to make sure iwe are dealing with a mouse.
|
* to be ID bits so use them to make sure we are
|
||||||
|
* dealing with a mouse.
|
||||||
* gamepad is connected. This is important since
|
* gamepad is connected. This is important since
|
||||||
* my SNES gamepad sends 1's for bits 16-31, which
|
* my SNES gamepad sends 1's for bits 16-31, which
|
||||||
* cause the mouse pointer to quickly move to the
|
* cause the mouse pointer to quickly move to the
|
||||||
|
|
@ -310,10 +450,15 @@ static void gc_nes_process_packet(struct gc *gc)
|
||||||
y_rel = -y_rel;
|
y_rel = -y_rel;
|
||||||
input_report_rel(dev, REL_Y, y_rel);
|
input_report_rel(dev, REL_Y, y_rel);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
input_sync(dev);
|
input_sync(dev);
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -340,29 +485,35 @@ static void gc_multi_read_packet(struct gc *gc, int length, unsigned char *data)
|
||||||
static void gc_multi_process_packet(struct gc *gc)
|
static void gc_multi_process_packet(struct gc *gc)
|
||||||
{
|
{
|
||||||
unsigned char data[GC_MULTI2_LENGTH];
|
unsigned char data[GC_MULTI2_LENGTH];
|
||||||
|
int data_len = gc->pad_count[GC_MULTI2] ? GC_MULTI2_LENGTH : GC_MULTI_LENGTH;
|
||||||
|
struct gc_pad *pad;
|
||||||
struct input_dev *dev;
|
struct input_dev *dev;
|
||||||
int i, s;
|
int i, s;
|
||||||
|
|
||||||
gc_multi_read_packet(gc, gc->pads[GC_MULTI2] ? GC_MULTI2_LENGTH : GC_MULTI_LENGTH, data);
|
gc_multi_read_packet(gc, data_len, data);
|
||||||
|
|
||||||
for (i = 0; i < GC_MAX_DEVICES; i++) {
|
for (i = 0; i < GC_MAX_DEVICES; i++) {
|
||||||
|
pad = &gc->pads[i];
|
||||||
dev = gc->dev[i];
|
dev = pad->dev;
|
||||||
if (!dev)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
s = gc_status_bit[i];
|
s = gc_status_bit[i];
|
||||||
|
|
||||||
if (s & (gc->pads[GC_MULTI] | gc->pads[GC_MULTI2])) {
|
switch (pad->type) {
|
||||||
input_report_abs(dev, ABS_X, !(s & data[2]) - !(s & data[3]));
|
case GC_MULTI2:
|
||||||
input_report_abs(dev, ABS_Y, !(s & data[0]) - !(s & data[1]));
|
|
||||||
input_report_key(dev, BTN_TRIGGER, s & data[4]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (s & gc->pads[GC_MULTI2])
|
|
||||||
input_report_key(dev, BTN_THUMB, s & data[5]);
|
input_report_key(dev, BTN_THUMB, s & data[5]);
|
||||||
|
/* fall through */
|
||||||
|
|
||||||
|
case GC_MULTI:
|
||||||
|
input_report_abs(dev, ABS_X,
|
||||||
|
!(s & data[2]) - !(s & data[3]));
|
||||||
|
input_report_abs(dev, ABS_Y,
|
||||||
|
!(s & data[0]) - !(s & data[1]));
|
||||||
|
input_report_key(dev, BTN_TRIGGER, s & data[4]);
|
||||||
input_sync(dev);
|
input_sync(dev);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -398,30 +549,41 @@ static int gc_psx_delay = GC_PSX_DELAY;
|
||||||
module_param_named(psx_delay, gc_psx_delay, uint, 0);
|
module_param_named(psx_delay, gc_psx_delay, uint, 0);
|
||||||
MODULE_PARM_DESC(psx_delay, "Delay when accessing Sony PSX controller (usecs)");
|
MODULE_PARM_DESC(psx_delay, "Delay when accessing Sony PSX controller (usecs)");
|
||||||
|
|
||||||
static short gc_psx_abs[] = { ABS_X, ABS_Y, ABS_RX, ABS_RY, ABS_HAT0X, ABS_HAT0Y };
|
static const short gc_psx_abs[] = {
|
||||||
static short gc_psx_btn[] = { BTN_TL, BTN_TR, BTN_TL2, BTN_TR2, BTN_A, BTN_B, BTN_X, BTN_Y,
|
ABS_X, ABS_Y, ABS_RX, ABS_RY, ABS_HAT0X, ABS_HAT0Y
|
||||||
BTN_START, BTN_SELECT, BTN_THUMBL, BTN_THUMBR };
|
};
|
||||||
static short gc_psx_ddr_btn[] = { BTN_0, BTN_1, BTN_2, BTN_3 };
|
static const short gc_psx_btn[] = {
|
||||||
|
BTN_TL, BTN_TR, BTN_TL2, BTN_TR2, BTN_A, BTN_B, BTN_X, BTN_Y,
|
||||||
|
BTN_START, BTN_SELECT, BTN_THUMBL, BTN_THUMBR
|
||||||
|
};
|
||||||
|
static const short gc_psx_ddr_btn[] = { BTN_0, BTN_1, BTN_2, BTN_3 };
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* gc_psx_command() writes 8bit command and reads 8bit data from
|
* gc_psx_command() writes 8bit command and reads 8bit data from
|
||||||
* the psx pad.
|
* the psx pad.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static void gc_psx_command(struct gc *gc, int b, unsigned char data[GC_MAX_DEVICES])
|
static void gc_psx_command(struct gc *gc, int b, unsigned char *data)
|
||||||
{
|
{
|
||||||
|
struct parport *port = gc->pd->port;
|
||||||
int i, j, cmd, read;
|
int i, j, cmd, read;
|
||||||
|
|
||||||
for (i = 0; i < GC_MAX_DEVICES; i++)
|
memset(data, 0, GC_MAX_DEVICES);
|
||||||
data[i] = 0;
|
|
||||||
|
|
||||||
for (i = 0; i < GC_PSX_LENGTH; i++, b >>= 1) {
|
for (i = 0; i < GC_PSX_LENGTH; i++, b >>= 1) {
|
||||||
cmd = (b & 1) ? GC_PSX_COMMAND : 0;
|
cmd = (b & 1) ? GC_PSX_COMMAND : 0;
|
||||||
parport_write_data(gc->pd->port, cmd | GC_PSX_POWER);
|
parport_write_data(port, cmd | GC_PSX_POWER);
|
||||||
udelay(gc_psx_delay);
|
udelay(gc_psx_delay);
|
||||||
read = parport_read_status(gc->pd->port) ^ 0x80;
|
|
||||||
for (j = 0; j < GC_MAX_DEVICES; j++)
|
read = parport_read_status(port) ^ 0x80;
|
||||||
data[j] |= (read & gc_status_bit[j] & (gc->pads[GC_PSX] | gc->pads[GC_DDR])) ? (1 << i) : 0;
|
|
||||||
|
for (j = 0; j < GC_MAX_DEVICES; j++) {
|
||||||
|
struct gc_pad *pad = &gc->pads[i];
|
||||||
|
|
||||||
|
if (pad->type == GC_PSX || pad->type == GC_DDR)
|
||||||
|
data[j] |= (read & gc_status_bit[j]) ? (1 << i) : 0;
|
||||||
|
}
|
||||||
|
|
||||||
parport_write_data(gc->pd->port, cmd | GC_PSX_CLOCK | GC_PSX_POWER);
|
parport_write_data(gc->pd->port, cmd | GC_PSX_CLOCK | GC_PSX_POWER);
|
||||||
udelay(gc_psx_delay);
|
udelay(gc_psx_delay);
|
||||||
}
|
}
|
||||||
|
|
@ -432,16 +594,19 @@ static void gc_psx_command(struct gc *gc, int b, unsigned char data[GC_MAX_DEVIC
|
||||||
* device identifier code.
|
* device identifier code.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static void gc_psx_read_packet(struct gc *gc, unsigned char data[GC_MAX_DEVICES][GC_PSX_BYTES],
|
static void gc_psx_read_packet(struct gc *gc,
|
||||||
|
unsigned char data[GC_MAX_DEVICES][GC_PSX_BYTES],
|
||||||
unsigned char id[GC_MAX_DEVICES])
|
unsigned char id[GC_MAX_DEVICES])
|
||||||
{
|
{
|
||||||
int i, j, max_len = 0;
|
int i, j, max_len = 0;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
unsigned char data2[GC_MAX_DEVICES];
|
unsigned char data2[GC_MAX_DEVICES];
|
||||||
|
|
||||||
parport_write_data(gc->pd->port, GC_PSX_CLOCK | GC_PSX_SELECT | GC_PSX_POWER); /* Select pad */
|
/* Select pad */
|
||||||
|
parport_write_data(gc->pd->port, GC_PSX_CLOCK | GC_PSX_SELECT | GC_PSX_POWER);
|
||||||
udelay(gc_psx_delay);
|
udelay(gc_psx_delay);
|
||||||
parport_write_data(gc->pd->port, GC_PSX_CLOCK | GC_PSX_POWER); /* Deselect, begin command */
|
/* Deselect, begin command */
|
||||||
|
parport_write_data(gc->pd->port, GC_PSX_CLOCK | GC_PSX_POWER);
|
||||||
udelay(gc_psx_delay);
|
udelay(gc_psx_delay);
|
||||||
|
|
||||||
local_irq_save(flags);
|
local_irq_save(flags);
|
||||||
|
|
@ -450,13 +615,19 @@ static void gc_psx_read_packet(struct gc *gc, unsigned char data[GC_MAX_DEVICES]
|
||||||
gc_psx_command(gc, 0x42, id); /* Get device ids */
|
gc_psx_command(gc, 0x42, id); /* Get device ids */
|
||||||
gc_psx_command(gc, 0, data2); /* Dump status */
|
gc_psx_command(gc, 0, data2); /* Dump status */
|
||||||
|
|
||||||
for (i =0; i < GC_MAX_DEVICES; i++) /* Find the longest pad */
|
/* Find the longest pad */
|
||||||
if((gc_status_bit[i] & (gc->pads[GC_PSX] | gc->pads[GC_DDR]))
|
for (i = 0; i < GC_MAX_DEVICES; i++) {
|
||||||
&& (GC_PSX_LEN(id[i]) > max_len)
|
struct gc_pad *pad = &gc->pads[i];
|
||||||
&& (GC_PSX_LEN(id[i]) <= GC_PSX_BYTES))
|
|
||||||
max_len = GC_PSX_LEN(id[i]);
|
|
||||||
|
|
||||||
for (i = 0; i < max_len; i++) { /* Read in all the data */
|
if ((pad->type == GC_PSX || pad->type == GC_DDR) &&
|
||||||
|
GC_PSX_LEN(id[i]) > max_len &&
|
||||||
|
GC_PSX_LEN(id[i]) <= GC_PSX_BYTES) {
|
||||||
|
max_len = GC_PSX_LEN(id[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read in all the data */
|
||||||
|
for (i = 0; i < max_len; i++) {
|
||||||
gc_psx_command(gc, 0, data2);
|
gc_psx_command(gc, 0, data2);
|
||||||
for (j = 0; j < GC_MAX_DEVICES; j++)
|
for (j = 0; j < GC_MAX_DEVICES; j++)
|
||||||
data[j][i] = data2[j];
|
data[j][i] = data2[j];
|
||||||
|
|
@ -466,86 +637,104 @@ static void gc_psx_read_packet(struct gc *gc, unsigned char data[GC_MAX_DEVICES]
|
||||||
|
|
||||||
parport_write_data(gc->pd->port, GC_PSX_CLOCK | GC_PSX_SELECT | GC_PSX_POWER);
|
parport_write_data(gc->pd->port, GC_PSX_CLOCK | GC_PSX_SELECT | GC_PSX_POWER);
|
||||||
|
|
||||||
for(i = 0; i < GC_MAX_DEVICES; i++) /* Set id's to the real value */
|
/* Set id's to the real value */
|
||||||
|
for (i = 0; i < GC_MAX_DEVICES; i++)
|
||||||
id[i] = GC_PSX_ID(id[i]);
|
id[i] = GC_PSX_ID(id[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void gc_psx_process_packet(struct gc *gc)
|
static void gc_psx_report_one(struct gc_pad *pad, unsigned char psx_type,
|
||||||
|
unsigned char *data)
|
||||||
{
|
{
|
||||||
unsigned char data[GC_MAX_DEVICES][GC_PSX_BYTES];
|
struct input_dev *dev = pad->dev;
|
||||||
unsigned char id[GC_MAX_DEVICES];
|
int i;
|
||||||
struct input_dev *dev;
|
|
||||||
int i, j;
|
|
||||||
|
|
||||||
gc_psx_read_packet(gc, data, id);
|
switch (psx_type) {
|
||||||
|
|
||||||
for (i = 0; i < GC_MAX_DEVICES; i++) {
|
|
||||||
|
|
||||||
dev = gc->dev[i];
|
|
||||||
if (!dev)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
switch (id[i]) {
|
|
||||||
|
|
||||||
case GC_PSX_RUMBLE:
|
case GC_PSX_RUMBLE:
|
||||||
|
|
||||||
input_report_key(dev, BTN_THUMBL, ~data[i][0] & 0x04);
|
input_report_key(dev, BTN_THUMBL, ~data[0] & 0x04);
|
||||||
input_report_key(dev, BTN_THUMBR, ~data[i][0] & 0x02);
|
input_report_key(dev, BTN_THUMBR, ~data[0] & 0x02);
|
||||||
|
|
||||||
case GC_PSX_NEGCON:
|
case GC_PSX_NEGCON:
|
||||||
case GC_PSX_ANALOG:
|
case GC_PSX_ANALOG:
|
||||||
|
|
||||||
if (gc->pads[GC_DDR] & gc_status_bit[i]) {
|
if (pad->type == GC_DDR) {
|
||||||
for(j = 0; j < 4; j++)
|
for (i = 0; i < 4; i++)
|
||||||
input_report_key(dev, gc_psx_ddr_btn[j], ~data[i][0] & (0x10 << j));
|
input_report_key(dev, gc_psx_ddr_btn[i],
|
||||||
|
~data[0] & (0x10 << i));
|
||||||
} else {
|
} else {
|
||||||
for (j = 0; j < 4; j++)
|
for (i = 0; i < 4; i++)
|
||||||
input_report_abs(dev, gc_psx_abs[j + 2], data[i][j + 2]);
|
input_report_abs(dev, gc_psx_abs[i + 2],
|
||||||
|
data[i + 2]);
|
||||||
|
|
||||||
input_report_abs(dev, ABS_X, 128 + !(data[i][0] & 0x20) * 127 - !(data[i][0] & 0x80) * 128);
|
input_report_abs(dev, ABS_X,
|
||||||
input_report_abs(dev, ABS_Y, 128 + !(data[i][0] & 0x40) * 127 - !(data[i][0] & 0x10) * 128);
|
!!(data[0] & 0x80) * 128 + !(data[0] & 0x20) * 127);
|
||||||
|
input_report_abs(dev, ABS_Y,
|
||||||
|
!!(data[0] & 0x10) * 128 + !(data[0] & 0x40) * 127);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (j = 0; j < 8; j++)
|
for (i = 0; i < 8; i++)
|
||||||
input_report_key(dev, gc_psx_btn[j], ~data[i][1] & (1 << j));
|
input_report_key(dev, gc_psx_btn[i], ~data[1] & (1 << i));
|
||||||
|
|
||||||
input_report_key(dev, BTN_START, ~data[i][0] & 0x08);
|
input_report_key(dev, BTN_START, ~data[0] & 0x08);
|
||||||
input_report_key(dev, BTN_SELECT, ~data[i][0] & 0x01);
|
input_report_key(dev, BTN_SELECT, ~data[0] & 0x01);
|
||||||
|
|
||||||
input_sync(dev);
|
input_sync(dev);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GC_PSX_NORMAL:
|
case GC_PSX_NORMAL:
|
||||||
if (gc->pads[GC_DDR] & gc_status_bit[i]) {
|
|
||||||
for(j = 0; j < 4; j++)
|
|
||||||
input_report_key(dev, gc_psx_ddr_btn[j], ~data[i][0] & (0x10 << j));
|
|
||||||
} else {
|
|
||||||
input_report_abs(dev, ABS_X, 128 + !(data[i][0] & 0x20) * 127 - !(data[i][0] & 0x80) * 128);
|
|
||||||
input_report_abs(dev, ABS_Y, 128 + !(data[i][0] & 0x40) * 127 - !(data[i][0] & 0x10) * 128);
|
|
||||||
|
|
||||||
/* for some reason if the extra axes are left unset they drift */
|
if (pad->type == GC_DDR) {
|
||||||
/* for (j = 0; j < 4; j++)
|
for (i = 0; i < 4; i++)
|
||||||
input_report_abs(dev, gc_psx_abs[j + 2], 128);
|
input_report_key(dev, gc_psx_ddr_btn[i],
|
||||||
|
~data[0] & (0x10 << i));
|
||||||
|
} else {
|
||||||
|
input_report_abs(dev, ABS_X,
|
||||||
|
!!(data[0] & 0x80) * 128 + !(data[0] & 0x20) * 127);
|
||||||
|
input_report_abs(dev, ABS_Y,
|
||||||
|
!!(data[0] & 0x10) * 128 + !(data[0] & 0x40) * 127);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For some reason if the extra axes are left unset
|
||||||
|
* they drift.
|
||||||
|
* for (i = 0; i < 4; i++)
|
||||||
|
input_report_abs(dev, gc_psx_abs[i + 2], 128);
|
||||||
* This needs to be debugged properly,
|
* This needs to be debugged properly,
|
||||||
* maybe fuzz processing needs to be done in input_sync()
|
* maybe fuzz processing needs to be done
|
||||||
|
* in input_sync()
|
||||||
* --vojtech
|
* --vojtech
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
for (j = 0; j < 8; j++)
|
for (i = 0; i < 8; i++)
|
||||||
input_report_key(dev, gc_psx_btn[j], ~data[i][1] & (1 << j));
|
input_report_key(dev, gc_psx_btn[i], ~data[1] & (1 << i));
|
||||||
|
|
||||||
input_report_key(dev, BTN_START, ~data[i][0] & 0x08);
|
input_report_key(dev, BTN_START, ~data[0] & 0x08);
|
||||||
input_report_key(dev, BTN_SELECT, ~data[i][0] & 0x01);
|
input_report_key(dev, BTN_SELECT, ~data[0] & 0x01);
|
||||||
|
|
||||||
input_sync(dev);
|
input_sync(dev);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0: /* not a pad, ignore */
|
default: /* not a pad, ignore */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gc_psx_process_packet(struct gc *gc)
|
||||||
|
{
|
||||||
|
unsigned char data[GC_MAX_DEVICES][GC_PSX_BYTES];
|
||||||
|
unsigned char id[GC_MAX_DEVICES];
|
||||||
|
struct gc_pad *pad;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
gc_psx_read_packet(gc, data, id);
|
||||||
|
|
||||||
|
for (i = 0; i < GC_MAX_DEVICES; i++) {
|
||||||
|
pad = &gc->pads[i];
|
||||||
|
if (pad->type == GC_PSX || pad->type == GC_DDR)
|
||||||
|
gc_psx_report_one(pad, id[i], data[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -561,28 +750,31 @@ static void gc_timer(unsigned long private)
|
||||||
* N64 pads - must be read first, any read confuses them for 200 us
|
* N64 pads - must be read first, any read confuses them for 200 us
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (gc->pads[GC_N64])
|
if (gc->pad_count[GC_N64])
|
||||||
gc_n64_process_packet(gc);
|
gc_n64_process_packet(gc);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* NES and SNES pads or mouse
|
* NES and SNES pads or mouse
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (gc->pads[GC_NES] || gc->pads[GC_SNES] || gc->pads[GC_SNESMOUSE])
|
if (gc->pad_count[GC_NES] ||
|
||||||
|
gc->pad_count[GC_SNES] ||
|
||||||
|
gc->pad_count[GC_SNESMOUSE]) {
|
||||||
gc_nes_process_packet(gc);
|
gc_nes_process_packet(gc);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Multi and Multi2 joysticks
|
* Multi and Multi2 joysticks
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (gc->pads[GC_MULTI] || gc->pads[GC_MULTI2])
|
if (gc->pad_count[GC_MULTI] || gc->pad_count[GC_MULTI2])
|
||||||
gc_multi_process_packet(gc);
|
gc_multi_process_packet(gc);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* PSX controllers
|
* PSX controllers
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (gc->pads[GC_PSX] || gc->pads[GC_DDR])
|
if (gc->pad_count[GC_PSX] || gc->pad_count[GC_DDR])
|
||||||
gc_psx_process_packet(gc);
|
gc_psx_process_packet(gc);
|
||||||
|
|
||||||
mod_timer(&gc->timer, jiffies + GC_REFRESH_TIME);
|
mod_timer(&gc->timer, jiffies + GC_REFRESH_TIME);
|
||||||
|
|
@ -622,25 +814,29 @@ static void gc_close(struct input_dev *dev)
|
||||||
|
|
||||||
static int __init gc_setup_pad(struct gc *gc, int idx, int pad_type)
|
static int __init gc_setup_pad(struct gc *gc, int idx, int pad_type)
|
||||||
{
|
{
|
||||||
|
struct gc_pad *pad = &gc->pads[idx];
|
||||||
struct input_dev *input_dev;
|
struct input_dev *input_dev;
|
||||||
int i;
|
int i;
|
||||||
|
int err;
|
||||||
if (!pad_type)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (pad_type < 1 || pad_type > GC_MAX) {
|
if (pad_type < 1 || pad_type > GC_MAX) {
|
||||||
printk(KERN_WARNING "gamecon.c: Pad type %d unknown\n", pad_type);
|
pr_err("Pad type %d unknown\n", pad_type);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
gc->dev[idx] = input_dev = input_allocate_device();
|
pad->dev = input_dev = input_allocate_device();
|
||||||
if (!input_dev) {
|
if (!input_dev) {
|
||||||
printk(KERN_ERR "gamecon.c: Not enough memory for input device\n");
|
pr_err("Not enough memory for input device\n");
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pad->type = pad_type;
|
||||||
|
|
||||||
|
snprintf(pad->phys, sizeof(pad->phys),
|
||||||
|
"%s/input%d", gc->pd->port->name, idx);
|
||||||
|
|
||||||
input_dev->name = gc_names[pad_type];
|
input_dev->name = gc_names[pad_type];
|
||||||
input_dev->phys = gc->phys[idx];
|
input_dev->phys = pad->phys;
|
||||||
input_dev->id.bustype = BUS_PARPORT;
|
input_dev->id.bustype = BUS_PARPORT;
|
||||||
input_dev->id.vendor = 0x0001;
|
input_dev->id.vendor = 0x0001;
|
||||||
input_dev->id.product = pad_type;
|
input_dev->id.product = pad_type;
|
||||||
|
|
@ -659,61 +855,76 @@ static int __init gc_setup_pad(struct gc *gc, int idx, int pad_type)
|
||||||
} else
|
} else
|
||||||
input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
|
input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
|
||||||
|
|
||||||
gc->pads[0] |= gc_status_bit[idx];
|
gc->pad_count[pad_type]++;
|
||||||
gc->pads[pad_type] |= gc_status_bit[idx];
|
|
||||||
|
|
||||||
switch (pad_type) {
|
switch (pad_type) {
|
||||||
|
|
||||||
case GC_N64:
|
case GC_N64:
|
||||||
for (i = 0; i < 10; i++)
|
for (i = 0; i < 10; i++)
|
||||||
set_bit(gc_n64_btn[i], input_dev->keybit);
|
__set_bit(gc_n64_btn[i], input_dev->keybit);
|
||||||
|
|
||||||
for (i = 0; i < 2; i++) {
|
for (i = 0; i < 2; i++) {
|
||||||
input_set_abs_params(input_dev, ABS_X + i, -127, 126, 0, 2);
|
input_set_abs_params(input_dev, ABS_X + i, -127, 126, 0, 2);
|
||||||
input_set_abs_params(input_dev, ABS_HAT0X + i, -1, 1, 0, 0);
|
input_set_abs_params(input_dev, ABS_HAT0X + i, -1, 1, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = gc_n64_init_ff(input_dev, idx);
|
||||||
|
if (err) {
|
||||||
|
pr_warning("Failed to initiate rumble for N64 device %d\n", idx);
|
||||||
|
goto err_free_dev;
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GC_SNESMOUSE:
|
case GC_SNESMOUSE:
|
||||||
set_bit(BTN_LEFT, input_dev->keybit);
|
__set_bit(BTN_LEFT, input_dev->keybit);
|
||||||
set_bit(BTN_RIGHT, input_dev->keybit);
|
__set_bit(BTN_RIGHT, input_dev->keybit);
|
||||||
set_bit(REL_X, input_dev->relbit);
|
__set_bit(REL_X, input_dev->relbit);
|
||||||
set_bit(REL_Y, input_dev->relbit);
|
__set_bit(REL_Y, input_dev->relbit);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GC_SNES:
|
case GC_SNES:
|
||||||
for (i = 4; i < 8; i++)
|
for (i = 4; i < 8; i++)
|
||||||
set_bit(gc_snes_btn[i], input_dev->keybit);
|
__set_bit(gc_snes_btn[i], input_dev->keybit);
|
||||||
case GC_NES:
|
case GC_NES:
|
||||||
for (i = 0; i < 4; i++)
|
for (i = 0; i < 4; i++)
|
||||||
set_bit(gc_snes_btn[i], input_dev->keybit);
|
__set_bit(gc_snes_btn[i], input_dev->keybit);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GC_MULTI2:
|
case GC_MULTI2:
|
||||||
set_bit(BTN_THUMB, input_dev->keybit);
|
__set_bit(BTN_THUMB, input_dev->keybit);
|
||||||
case GC_MULTI:
|
case GC_MULTI:
|
||||||
set_bit(BTN_TRIGGER, input_dev->keybit);
|
__set_bit(BTN_TRIGGER, input_dev->keybit);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GC_PSX:
|
case GC_PSX:
|
||||||
for (i = 0; i < 6; i++)
|
for (i = 0; i < 6; i++)
|
||||||
input_set_abs_params(input_dev, gc_psx_abs[i], 4, 252, 0, 2);
|
input_set_abs_params(input_dev,
|
||||||
|
gc_psx_abs[i], 4, 252, 0, 2);
|
||||||
for (i = 0; i < 12; i++)
|
for (i = 0; i < 12; i++)
|
||||||
set_bit(gc_psx_btn[i], input_dev->keybit);
|
__set_bit(gc_psx_btn[i], input_dev->keybit);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GC_DDR:
|
case GC_DDR:
|
||||||
for (i = 0; i < 4; i++)
|
for (i = 0; i < 4; i++)
|
||||||
set_bit(gc_psx_ddr_btn[i], input_dev->keybit);
|
__set_bit(gc_psx_ddr_btn[i], input_dev->keybit);
|
||||||
for (i = 0; i < 12; i++)
|
for (i = 0; i < 12; i++)
|
||||||
set_bit(gc_psx_btn[i], input_dev->keybit);
|
__set_bit(gc_psx_btn[i], input_dev->keybit);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = input_register_device(pad->dev);
|
||||||
|
if (err)
|
||||||
|
goto err_free_dev;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
err_free_dev:
|
||||||
|
input_free_device(pad->dev);
|
||||||
|
pad->dev = NULL;
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct gc __init *gc_probe(int parport, int *pads, int n_pads)
|
static struct gc __init *gc_probe(int parport, int *pads, int n_pads)
|
||||||
|
|
@ -722,52 +933,47 @@ static struct gc __init *gc_probe(int parport, int *pads, int n_pads)
|
||||||
struct parport *pp;
|
struct parport *pp;
|
||||||
struct pardevice *pd;
|
struct pardevice *pd;
|
||||||
int i;
|
int i;
|
||||||
|
int count = 0;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
pp = parport_find_number(parport);
|
pp = parport_find_number(parport);
|
||||||
if (!pp) {
|
if (!pp) {
|
||||||
printk(KERN_ERR "gamecon.c: no such parport\n");
|
pr_err("no such parport %d\n", parport);
|
||||||
err = -EINVAL;
|
err = -EINVAL;
|
||||||
goto err_out;
|
goto err_out;
|
||||||
}
|
}
|
||||||
|
|
||||||
pd = parport_register_device(pp, "gamecon", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL);
|
pd = parport_register_device(pp, "gamecon", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL);
|
||||||
if (!pd) {
|
if (!pd) {
|
||||||
printk(KERN_ERR "gamecon.c: parport busy already - lp.o loaded?\n");
|
pr_err("parport busy already - lp.o loaded?\n");
|
||||||
err = -EBUSY;
|
err = -EBUSY;
|
||||||
goto err_put_pp;
|
goto err_put_pp;
|
||||||
}
|
}
|
||||||
|
|
||||||
gc = kzalloc(sizeof(struct gc), GFP_KERNEL);
|
gc = kzalloc(sizeof(struct gc), GFP_KERNEL);
|
||||||
if (!gc) {
|
if (!gc) {
|
||||||
printk(KERN_ERR "gamecon.c: Not enough memory\n");
|
pr_err("Not enough memory\n");
|
||||||
err = -ENOMEM;
|
err = -ENOMEM;
|
||||||
goto err_unreg_pardev;
|
goto err_unreg_pardev;
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex_init(&gc->mutex);
|
mutex_init(&gc->mutex);
|
||||||
gc->pd = pd;
|
gc->pd = pd;
|
||||||
init_timer(&gc->timer);
|
setup_timer(&gc->timer, gc_timer, (long) gc);
|
||||||
gc->timer.data = (long) gc;
|
|
||||||
gc->timer.function = gc_timer;
|
|
||||||
|
|
||||||
for (i = 0; i < n_pads && i < GC_MAX_DEVICES; i++) {
|
for (i = 0; i < n_pads && i < GC_MAX_DEVICES; i++) {
|
||||||
if (!pads[i])
|
if (!pads[i])
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
snprintf(gc->phys[i], sizeof(gc->phys[i]),
|
|
||||||
"%s/input%d", gc->pd->port->name, i);
|
|
||||||
err = gc_setup_pad(gc, i, pads[i]);
|
err = gc_setup_pad(gc, i, pads[i]);
|
||||||
if (err)
|
if (err)
|
||||||
goto err_unreg_devs;
|
goto err_unreg_devs;
|
||||||
|
|
||||||
err = input_register_device(gc->dev[i]);
|
count++;
|
||||||
if (err)
|
|
||||||
goto err_free_dev;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!gc->pads[0]) {
|
if (count == 0) {
|
||||||
printk(KERN_ERR "gamecon.c: No valid devices specified\n");
|
pr_err("No valid devices specified\n");
|
||||||
err = -EINVAL;
|
err = -EINVAL;
|
||||||
goto err_free_gc;
|
goto err_free_gc;
|
||||||
}
|
}
|
||||||
|
|
@ -775,12 +981,10 @@ static struct gc __init *gc_probe(int parport, int *pads, int n_pads)
|
||||||
parport_put_port(pp);
|
parport_put_port(pp);
|
||||||
return gc;
|
return gc;
|
||||||
|
|
||||||
err_free_dev:
|
|
||||||
input_free_device(gc->dev[i]);
|
|
||||||
err_unreg_devs:
|
err_unreg_devs:
|
||||||
while (--i >= 0)
|
while (--i >= 0)
|
||||||
if (gc->dev[i])
|
if (gc->pads[i].dev)
|
||||||
input_unregister_device(gc->dev[i]);
|
input_unregister_device(gc->pads[i].dev);
|
||||||
err_free_gc:
|
err_free_gc:
|
||||||
kfree(gc);
|
kfree(gc);
|
||||||
err_unreg_pardev:
|
err_unreg_pardev:
|
||||||
|
|
@ -796,8 +1000,8 @@ static void gc_remove(struct gc *gc)
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < GC_MAX_DEVICES; i++)
|
for (i = 0; i < GC_MAX_DEVICES; i++)
|
||||||
if (gc->dev[i])
|
if (gc->pads[i].dev)
|
||||||
input_unregister_device(gc->dev[i]);
|
input_unregister_device(gc->pads[i].dev);
|
||||||
parport_unregister_device(gc->pd);
|
parport_unregister_device(gc->pd);
|
||||||
kfree(gc);
|
kfree(gc);
|
||||||
}
|
}
|
||||||
|
|
@ -813,7 +1017,7 @@ static int __init gc_init(void)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (gc_cfg[i].nargs < 2) {
|
if (gc_cfg[i].nargs < 2) {
|
||||||
printk(KERN_ERR "gamecon.c: at least one device must be specified\n");
|
pr_err("at least one device must be specified\n");
|
||||||
err = -EINVAL;
|
err = -EINVAL;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -86,9 +86,8 @@
|
||||||
|
|
||||||
/* xbox d-pads should map to buttons, as is required for DDR pads
|
/* xbox d-pads should map to buttons, as is required for DDR pads
|
||||||
but we map them to axes when possible to simplify things */
|
but we map them to axes when possible to simplify things */
|
||||||
#define MAP_DPAD_TO_BUTTONS 0
|
#define MAP_DPAD_TO_BUTTONS (1 << 0)
|
||||||
#define MAP_DPAD_TO_AXES 1
|
#define MAP_TRIGGERS_TO_BUTTONS (1 << 1)
|
||||||
#define MAP_DPAD_UNKNOWN 2
|
|
||||||
|
|
||||||
#define XTYPE_XBOX 0
|
#define XTYPE_XBOX 0
|
||||||
#define XTYPE_XBOX360 1
|
#define XTYPE_XBOX360 1
|
||||||
|
|
@ -99,57 +98,61 @@ static int dpad_to_buttons;
|
||||||
module_param(dpad_to_buttons, bool, S_IRUGO);
|
module_param(dpad_to_buttons, bool, S_IRUGO);
|
||||||
MODULE_PARM_DESC(dpad_to_buttons, "Map D-PAD to buttons rather than axes for unknown pads");
|
MODULE_PARM_DESC(dpad_to_buttons, "Map D-PAD to buttons rather than axes for unknown pads");
|
||||||
|
|
||||||
|
static int triggers_to_buttons;
|
||||||
|
module_param(triggers_to_buttons, bool, S_IRUGO);
|
||||||
|
MODULE_PARM_DESC(triggers_to_buttons, "Map triggers to buttons rather than axes for unknown pads");
|
||||||
|
|
||||||
static const struct xpad_device {
|
static const struct xpad_device {
|
||||||
u16 idVendor;
|
u16 idVendor;
|
||||||
u16 idProduct;
|
u16 idProduct;
|
||||||
char *name;
|
char *name;
|
||||||
u8 dpad_mapping;
|
u8 mapping;
|
||||||
u8 xtype;
|
u8 xtype;
|
||||||
} xpad_device[] = {
|
} xpad_device[] = {
|
||||||
{ 0x045e, 0x0202, "Microsoft X-Box pad v1 (US)", MAP_DPAD_TO_AXES, XTYPE_XBOX },
|
{ 0x045e, 0x0202, "Microsoft X-Box pad v1 (US)", 0, XTYPE_XBOX },
|
||||||
{ 0x045e, 0x0289, "Microsoft X-Box pad v2 (US)", MAP_DPAD_TO_AXES, XTYPE_XBOX },
|
{ 0x045e, 0x0289, "Microsoft X-Box pad v2 (US)", 0, XTYPE_XBOX },
|
||||||
{ 0x045e, 0x0285, "Microsoft X-Box pad (Japan)", MAP_DPAD_TO_AXES, XTYPE_XBOX },
|
{ 0x045e, 0x0285, "Microsoft X-Box pad (Japan)", 0, XTYPE_XBOX },
|
||||||
{ 0x045e, 0x0287, "Microsoft Xbox Controller S", MAP_DPAD_TO_AXES, XTYPE_XBOX },
|
{ 0x045e, 0x0287, "Microsoft Xbox Controller S", 0, XTYPE_XBOX },
|
||||||
{ 0x045e, 0x0719, "Xbox 360 Wireless Receiver", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360W },
|
{ 0x045e, 0x0719, "Xbox 360 Wireless Receiver", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360W },
|
||||||
{ 0x0c12, 0x8809, "RedOctane Xbox Dance Pad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },
|
{ 0x0c12, 0x8809, "RedOctane Xbox Dance Pad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },
|
||||||
{ 0x044f, 0x0f07, "Thrustmaster, Inc. Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
|
{ 0x044f, 0x0f07, "Thrustmaster, Inc. Controller", 0, XTYPE_XBOX },
|
||||||
{ 0x046d, 0xc242, "Logitech Chillstream Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX360 },
|
{ 0x046d, 0xc242, "Logitech Chillstream Controller", 0, XTYPE_XBOX360 },
|
||||||
{ 0x046d, 0xca84, "Logitech Xbox Cordless Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
|
{ 0x046d, 0xca84, "Logitech Xbox Cordless Controller", 0, XTYPE_XBOX },
|
||||||
{ 0x046d, 0xca88, "Logitech Compact Controller for Xbox", MAP_DPAD_TO_AXES, XTYPE_XBOX },
|
{ 0x046d, 0xca88, "Logitech Compact Controller for Xbox", 0, XTYPE_XBOX },
|
||||||
{ 0x05fd, 0x1007, "Mad Catz Controller (unverified)", MAP_DPAD_TO_AXES, XTYPE_XBOX },
|
{ 0x05fd, 0x1007, "Mad Catz Controller (unverified)", 0, XTYPE_XBOX },
|
||||||
{ 0x05fd, 0x107a, "InterAct 'PowerPad Pro' X-Box pad (Germany)", MAP_DPAD_TO_AXES, XTYPE_XBOX },
|
{ 0x05fd, 0x107a, "InterAct 'PowerPad Pro' X-Box pad (Germany)", 0, XTYPE_XBOX },
|
||||||
{ 0x0738, 0x4516, "Mad Catz Control Pad", MAP_DPAD_TO_AXES, XTYPE_XBOX },
|
{ 0x0738, 0x4516, "Mad Catz Control Pad", 0, XTYPE_XBOX },
|
||||||
{ 0x0738, 0x4522, "Mad Catz LumiCON", MAP_DPAD_TO_AXES, XTYPE_XBOX },
|
{ 0x0738, 0x4522, "Mad Catz LumiCON", 0, XTYPE_XBOX },
|
||||||
{ 0x0738, 0x4526, "Mad Catz Control Pad Pro", MAP_DPAD_TO_AXES, XTYPE_XBOX },
|
{ 0x0738, 0x4526, "Mad Catz Control Pad Pro", 0, XTYPE_XBOX },
|
||||||
{ 0x0738, 0x4536, "Mad Catz MicroCON", MAP_DPAD_TO_AXES, XTYPE_XBOX },
|
{ 0x0738, 0x4536, "Mad Catz MicroCON", 0, XTYPE_XBOX },
|
||||||
{ 0x0738, 0x4540, "Mad Catz Beat Pad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },
|
{ 0x0738, 0x4540, "Mad Catz Beat Pad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },
|
||||||
{ 0x0738, 0x4556, "Mad Catz Lynx Wireless Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
|
{ 0x0738, 0x4556, "Mad Catz Lynx Wireless Controller", 0, XTYPE_XBOX },
|
||||||
{ 0x0738, 0x4716, "Mad Catz Wired Xbox 360 Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX360 },
|
{ 0x0738, 0x4716, "Mad Catz Wired Xbox 360 Controller", 0, XTYPE_XBOX360 },
|
||||||
{ 0x0738, 0x4738, "Mad Catz Wired Xbox 360 Controller (SFIV)", MAP_DPAD_TO_AXES, XTYPE_XBOX360 },
|
{ 0x0738, 0x4738, "Mad Catz Wired Xbox 360 Controller (SFIV)", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
|
||||||
{ 0x0738, 0x6040, "Mad Catz Beat Pad Pro", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },
|
{ 0x0738, 0x6040, "Mad Catz Beat Pad Pro", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },
|
||||||
{ 0x0c12, 0x8802, "Zeroplus Xbox Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
|
{ 0x0c12, 0x8802, "Zeroplus Xbox Controller", 0, XTYPE_XBOX },
|
||||||
{ 0x0c12, 0x880a, "Pelican Eclipse PL-2023", MAP_DPAD_TO_AXES, XTYPE_XBOX },
|
{ 0x0c12, 0x880a, "Pelican Eclipse PL-2023", 0, XTYPE_XBOX },
|
||||||
{ 0x0c12, 0x8810, "Zeroplus Xbox Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
|
{ 0x0c12, 0x8810, "Zeroplus Xbox Controller", 0, XTYPE_XBOX },
|
||||||
{ 0x0c12, 0x9902, "HAMA VibraX - *FAULTY HARDWARE*", MAP_DPAD_TO_AXES, XTYPE_XBOX },
|
{ 0x0c12, 0x9902, "HAMA VibraX - *FAULTY HARDWARE*", 0, XTYPE_XBOX },
|
||||||
{ 0x0e4c, 0x1097, "Radica Gamester Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
|
{ 0x0e4c, 0x1097, "Radica Gamester Controller", 0, XTYPE_XBOX },
|
||||||
{ 0x0e4c, 0x2390, "Radica Games Jtech Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
|
{ 0x0e4c, 0x2390, "Radica Games Jtech Controller", 0, XTYPE_XBOX },
|
||||||
{ 0x0e6f, 0x0003, "Logic3 Freebird wireless Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
|
{ 0x0e6f, 0x0003, "Logic3 Freebird wireless Controller", 0, XTYPE_XBOX },
|
||||||
{ 0x0e6f, 0x0005, "Eclipse wireless Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
|
{ 0x0e6f, 0x0005, "Eclipse wireless Controller", 0, XTYPE_XBOX },
|
||||||
{ 0x0e6f, 0x0006, "Edge wireless Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
|
{ 0x0e6f, 0x0006, "Edge wireless Controller", 0, XTYPE_XBOX },
|
||||||
{ 0x0e6f, 0x0006, "Pelican 'TSZ' Wired Xbox 360 Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX360 },
|
{ 0x0e6f, 0x0006, "Pelican 'TSZ' Wired Xbox 360 Controller", 0, XTYPE_XBOX360 },
|
||||||
{ 0x0e8f, 0x0201, "SmartJoy Frag Xpad/PS2 adaptor", MAP_DPAD_TO_AXES, XTYPE_XBOX },
|
{ 0x0e8f, 0x0201, "SmartJoy Frag Xpad/PS2 adaptor", 0, XTYPE_XBOX },
|
||||||
{ 0x0f30, 0x0202, "Joytech Advanced Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
|
{ 0x0f30, 0x0202, "Joytech Advanced Controller", 0, XTYPE_XBOX },
|
||||||
{ 0x0f30, 0x8888, "BigBen XBMiniPad Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
|
{ 0x0f30, 0x8888, "BigBen XBMiniPad Controller", 0, XTYPE_XBOX },
|
||||||
{ 0x102c, 0xff0c, "Joytech Wireless Advanced Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
|
{ 0x102c, 0xff0c, "Joytech Wireless Advanced Controller", 0, XTYPE_XBOX },
|
||||||
{ 0x12ab, 0x8809, "Xbox DDR dancepad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },
|
{ 0x12ab, 0x8809, "Xbox DDR dancepad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },
|
||||||
{ 0x1430, 0x4748, "RedOctane Guitar Hero X-plorer", MAP_DPAD_TO_AXES, XTYPE_XBOX360 },
|
{ 0x1430, 0x4748, "RedOctane Guitar Hero X-plorer", 0, XTYPE_XBOX360 },
|
||||||
{ 0x1430, 0x8888, "TX6500+ Dance Pad (first generation)", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },
|
{ 0x1430, 0x8888, "TX6500+ Dance Pad (first generation)", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },
|
||||||
{ 0x146b, 0x0601, "BigBen Interactive XBOX 360 Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX360 },
|
{ 0x146b, 0x0601, "BigBen Interactive XBOX 360 Controller", 0, XTYPE_XBOX360 },
|
||||||
{ 0x045e, 0x028e, "Microsoft X-Box 360 pad", MAP_DPAD_TO_AXES, XTYPE_XBOX360 },
|
{ 0x045e, 0x028e, "Microsoft X-Box 360 pad", 0, XTYPE_XBOX360 },
|
||||||
{ 0x1bad, 0x0003, "Harmonix Rock Band Drumkit", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 },
|
{ 0x1bad, 0x0003, "Harmonix Rock Band Drumkit", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 },
|
||||||
{ 0x0f0d, 0x0016, "Hori Real Arcade Pro.EX", MAP_DPAD_TO_AXES, XTYPE_XBOX360 },
|
{ 0x0f0d, 0x0016, "Hori Real Arcade Pro.EX", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
|
||||||
{ 0xffff, 0xffff, "Chinese-made Xbox Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
|
{ 0xffff, 0xffff, "Chinese-made Xbox Controller", 0, XTYPE_XBOX },
|
||||||
{ 0x0000, 0x0000, "Generic X-Box pad", MAP_DPAD_UNKNOWN, XTYPE_UNKNOWN }
|
{ 0x0000, 0x0000, "Generic X-Box pad", 0, XTYPE_UNKNOWN }
|
||||||
};
|
};
|
||||||
|
|
||||||
/* buttons shared with xbox and xbox360 */
|
/* buttons shared with xbox and xbox360 */
|
||||||
|
|
@ -165,13 +168,20 @@ static const signed short xpad_btn[] = {
|
||||||
-1 /* terminating entry */
|
-1 /* terminating entry */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* only used if MAP_DPAD_TO_BUTTONS */
|
/* used when dpad is mapped to nuttons */
|
||||||
static const signed short xpad_btn_pad[] = {
|
static const signed short xpad_btn_pad[] = {
|
||||||
BTN_LEFT, BTN_RIGHT, /* d-pad left, right */
|
BTN_LEFT, BTN_RIGHT, /* d-pad left, right */
|
||||||
BTN_0, BTN_1, /* d-pad up, down (XXX names??) */
|
BTN_0, BTN_1, /* d-pad up, down (XXX names??) */
|
||||||
-1 /* terminating entry */
|
-1 /* terminating entry */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* used when triggers are mapped to buttons */
|
||||||
|
static const signed short xpad_btn_triggers[] = {
|
||||||
|
BTN_TL2, BTN_TR2, /* triggers left/right */
|
||||||
|
-1
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
static const signed short xpad360_btn[] = { /* buttons for x360 controller */
|
static const signed short xpad360_btn[] = { /* buttons for x360 controller */
|
||||||
BTN_TL, BTN_TR, /* Button LB/RB */
|
BTN_TL, BTN_TR, /* Button LB/RB */
|
||||||
BTN_MODE, /* The big X button */
|
BTN_MODE, /* The big X button */
|
||||||
|
|
@ -181,16 +191,21 @@ static const signed short xpad360_btn[] = { /* buttons for x360 controller */
|
||||||
static const signed short xpad_abs[] = {
|
static const signed short xpad_abs[] = {
|
||||||
ABS_X, ABS_Y, /* left stick */
|
ABS_X, ABS_Y, /* left stick */
|
||||||
ABS_RX, ABS_RY, /* right stick */
|
ABS_RX, ABS_RY, /* right stick */
|
||||||
ABS_Z, ABS_RZ, /* triggers left/right */
|
|
||||||
-1 /* terminating entry */
|
-1 /* terminating entry */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* only used if MAP_DPAD_TO_AXES */
|
/* used when dpad is mapped to axes */
|
||||||
static const signed short xpad_abs_pad[] = {
|
static const signed short xpad_abs_pad[] = {
|
||||||
ABS_HAT0X, ABS_HAT0Y, /* d-pad axes */
|
ABS_HAT0X, ABS_HAT0Y, /* d-pad axes */
|
||||||
-1 /* terminating entry */
|
-1 /* terminating entry */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* used when triggers are mapped to axes */
|
||||||
|
static const signed short xpad_abs_triggers[] = {
|
||||||
|
ABS_Z, ABS_RZ, /* triggers left/right */
|
||||||
|
-1
|
||||||
|
};
|
||||||
|
|
||||||
/* Xbox 360 has a vendor-specific class, so we cannot match it with only
|
/* Xbox 360 has a vendor-specific class, so we cannot match it with only
|
||||||
* USB_INTERFACE_INFO (also specifically refused by USB subsystem), so we
|
* USB_INTERFACE_INFO (also specifically refused by USB subsystem), so we
|
||||||
* match against vendor id as well. Wired Xbox 360 devices have protocol 1,
|
* match against vendor id as well. Wired Xbox 360 devices have protocol 1,
|
||||||
|
|
@ -246,7 +261,7 @@ struct usb_xpad {
|
||||||
|
|
||||||
char phys[64]; /* physical device path */
|
char phys[64]; /* physical device path */
|
||||||
|
|
||||||
int dpad_mapping; /* map d-pad to buttons or to axes */
|
int mapping; /* map d-pad to buttons or to axes */
|
||||||
int xtype; /* type of xbox device */
|
int xtype; /* type of xbox device */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -277,20 +292,25 @@ static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *d
|
||||||
~(__s16) le16_to_cpup((__le16 *)(data + 18)));
|
~(__s16) le16_to_cpup((__le16 *)(data + 18)));
|
||||||
|
|
||||||
/* triggers left/right */
|
/* triggers left/right */
|
||||||
|
if (xpad->mapping & MAP_TRIGGERS_TO_BUTTONS) {
|
||||||
|
input_report_key(dev, BTN_TL2, data[10]);
|
||||||
|
input_report_key(dev, BTN_TR2, data[11]);
|
||||||
|
} else {
|
||||||
input_report_abs(dev, ABS_Z, data[10]);
|
input_report_abs(dev, ABS_Z, data[10]);
|
||||||
input_report_abs(dev, ABS_RZ, data[11]);
|
input_report_abs(dev, ABS_RZ, data[11]);
|
||||||
|
}
|
||||||
|
|
||||||
/* digital pad */
|
/* digital pad */
|
||||||
if (xpad->dpad_mapping == MAP_DPAD_TO_AXES) {
|
if (xpad->mapping & MAP_DPAD_TO_BUTTONS) {
|
||||||
input_report_abs(dev, ABS_HAT0X,
|
|
||||||
!!(data[2] & 0x08) - !!(data[2] & 0x04));
|
|
||||||
input_report_abs(dev, ABS_HAT0Y,
|
|
||||||
!!(data[2] & 0x02) - !!(data[2] & 0x01));
|
|
||||||
} else /* xpad->dpad_mapping == MAP_DPAD_TO_BUTTONS */ {
|
|
||||||
input_report_key(dev, BTN_LEFT, data[2] & 0x04);
|
input_report_key(dev, BTN_LEFT, data[2] & 0x04);
|
||||||
input_report_key(dev, BTN_RIGHT, data[2] & 0x08);
|
input_report_key(dev, BTN_RIGHT, data[2] & 0x08);
|
||||||
input_report_key(dev, BTN_0, data[2] & 0x01); /* up */
|
input_report_key(dev, BTN_0, data[2] & 0x01); /* up */
|
||||||
input_report_key(dev, BTN_1, data[2] & 0x02); /* down */
|
input_report_key(dev, BTN_1, data[2] & 0x02); /* down */
|
||||||
|
} else {
|
||||||
|
input_report_abs(dev, ABS_HAT0X,
|
||||||
|
!!(data[2] & 0x08) - !!(data[2] & 0x04));
|
||||||
|
input_report_abs(dev, ABS_HAT0Y,
|
||||||
|
!!(data[2] & 0x02) - !!(data[2] & 0x01));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* start/back buttons and stick press left/right */
|
/* start/back buttons and stick press left/right */
|
||||||
|
|
@ -328,17 +348,17 @@ static void xpad360_process_packet(struct usb_xpad *xpad,
|
||||||
struct input_dev *dev = xpad->dev;
|
struct input_dev *dev = xpad->dev;
|
||||||
|
|
||||||
/* digital pad */
|
/* digital pad */
|
||||||
if (xpad->dpad_mapping == MAP_DPAD_TO_AXES) {
|
if (xpad->mapping & MAP_DPAD_TO_BUTTONS) {
|
||||||
input_report_abs(dev, ABS_HAT0X,
|
|
||||||
!!(data[2] & 0x08) - !!(data[2] & 0x04));
|
|
||||||
input_report_abs(dev, ABS_HAT0Y,
|
|
||||||
!!(data[2] & 0x02) - !!(data[2] & 0x01));
|
|
||||||
} else if (xpad->dpad_mapping == MAP_DPAD_TO_BUTTONS) {
|
|
||||||
/* dpad as buttons (right, left, down, up) */
|
/* dpad as buttons (right, left, down, up) */
|
||||||
input_report_key(dev, BTN_LEFT, data[2] & 0x04);
|
input_report_key(dev, BTN_LEFT, data[2] & 0x04);
|
||||||
input_report_key(dev, BTN_RIGHT, data[2] & 0x08);
|
input_report_key(dev, BTN_RIGHT, data[2] & 0x08);
|
||||||
input_report_key(dev, BTN_0, data[2] & 0x01); /* up */
|
input_report_key(dev, BTN_0, data[2] & 0x01); /* up */
|
||||||
input_report_key(dev, BTN_1, data[2] & 0x02); /* down */
|
input_report_key(dev, BTN_1, data[2] & 0x02); /* down */
|
||||||
|
} else {
|
||||||
|
input_report_abs(dev, ABS_HAT0X,
|
||||||
|
!!(data[2] & 0x08) - !!(data[2] & 0x04));
|
||||||
|
input_report_abs(dev, ABS_HAT0Y,
|
||||||
|
!!(data[2] & 0x02) - !!(data[2] & 0x01));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* start/back buttons */
|
/* start/back buttons */
|
||||||
|
|
@ -371,8 +391,13 @@ static void xpad360_process_packet(struct usb_xpad *xpad,
|
||||||
~(__s16) le16_to_cpup((__le16 *)(data + 12)));
|
~(__s16) le16_to_cpup((__le16 *)(data + 12)));
|
||||||
|
|
||||||
/* triggers left/right */
|
/* triggers left/right */
|
||||||
|
if (xpad->mapping & MAP_TRIGGERS_TO_BUTTONS) {
|
||||||
|
input_report_key(dev, BTN_TL2, data[4]);
|
||||||
|
input_report_key(dev, BTN_TR2, data[5]);
|
||||||
|
} else {
|
||||||
input_report_abs(dev, ABS_Z, data[4]);
|
input_report_abs(dev, ABS_Z, data[4]);
|
||||||
input_report_abs(dev, ABS_RZ, data[5]);
|
input_report_abs(dev, ABS_RZ, data[5]);
|
||||||
|
}
|
||||||
|
|
||||||
input_sync(dev);
|
input_sync(dev);
|
||||||
}
|
}
|
||||||
|
|
@ -505,7 +530,7 @@ static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad)
|
||||||
struct usb_endpoint_descriptor *ep_irq_out;
|
struct usb_endpoint_descriptor *ep_irq_out;
|
||||||
int error = -ENOMEM;
|
int error = -ENOMEM;
|
||||||
|
|
||||||
if (xpad->xtype != XTYPE_XBOX360)
|
if (xpad->xtype != XTYPE_XBOX360 && xpad->xtype != XTYPE_XBOX)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
xpad->odata = usb_buffer_alloc(xpad->udev, XPAD_PKT_LEN,
|
xpad->odata = usb_buffer_alloc(xpad->udev, XPAD_PKT_LEN,
|
||||||
|
|
@ -535,13 +560,13 @@ static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad)
|
||||||
|
|
||||||
static void xpad_stop_output(struct usb_xpad *xpad)
|
static void xpad_stop_output(struct usb_xpad *xpad)
|
||||||
{
|
{
|
||||||
if (xpad->xtype == XTYPE_XBOX360)
|
if (xpad->xtype == XTYPE_XBOX360 || xpad->xtype == XTYPE_XBOX)
|
||||||
usb_kill_urb(xpad->irq_out);
|
usb_kill_urb(xpad->irq_out);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void xpad_deinit_output(struct usb_xpad *xpad)
|
static void xpad_deinit_output(struct usb_xpad *xpad)
|
||||||
{
|
{
|
||||||
if (xpad->xtype == XTYPE_XBOX360) {
|
if (xpad->xtype == XTYPE_XBOX360 || xpad->xtype == XTYPE_XBOX) {
|
||||||
usb_free_urb(xpad->irq_out);
|
usb_free_urb(xpad->irq_out);
|
||||||
usb_buffer_free(xpad->udev, XPAD_PKT_LEN,
|
usb_buffer_free(xpad->udev, XPAD_PKT_LEN,
|
||||||
xpad->odata, xpad->odata_dma);
|
xpad->odata, xpad->odata_dma);
|
||||||
|
|
@ -554,24 +579,45 @@ static void xpad_stop_output(struct usb_xpad *xpad) {}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_JOYSTICK_XPAD_FF
|
#ifdef CONFIG_JOYSTICK_XPAD_FF
|
||||||
static int xpad_play_effect(struct input_dev *dev, void *data,
|
static int xpad_play_effect(struct input_dev *dev, void *data, struct ff_effect *effect)
|
||||||
struct ff_effect *effect)
|
|
||||||
{
|
{
|
||||||
struct usb_xpad *xpad = input_get_drvdata(dev);
|
struct usb_xpad *xpad = input_get_drvdata(dev);
|
||||||
|
|
||||||
if (effect->type == FF_RUMBLE) {
|
if (effect->type == FF_RUMBLE) {
|
||||||
__u16 strong = effect->u.rumble.strong_magnitude;
|
__u16 strong = effect->u.rumble.strong_magnitude;
|
||||||
__u16 weak = effect->u.rumble.weak_magnitude;
|
__u16 weak = effect->u.rumble.weak_magnitude;
|
||||||
|
|
||||||
|
switch (xpad->xtype) {
|
||||||
|
|
||||||
|
case XTYPE_XBOX:
|
||||||
|
xpad->odata[0] = 0x00;
|
||||||
|
xpad->odata[1] = 0x06;
|
||||||
|
xpad->odata[2] = 0x00;
|
||||||
|
xpad->odata[3] = strong / 256; /* left actuator */
|
||||||
|
xpad->odata[4] = 0x00;
|
||||||
|
xpad->odata[5] = weak / 256; /* right actuator */
|
||||||
|
xpad->irq_out->transfer_buffer_length = 6;
|
||||||
|
|
||||||
|
return usb_submit_urb(xpad->irq_out, GFP_ATOMIC);
|
||||||
|
|
||||||
|
case XTYPE_XBOX360:
|
||||||
xpad->odata[0] = 0x00;
|
xpad->odata[0] = 0x00;
|
||||||
xpad->odata[1] = 0x08;
|
xpad->odata[1] = 0x08;
|
||||||
xpad->odata[2] = 0x00;
|
xpad->odata[2] = 0x00;
|
||||||
xpad->odata[3] = strong / 256;
|
xpad->odata[3] = strong / 256; /* left actuator? */
|
||||||
xpad->odata[4] = weak / 256;
|
xpad->odata[4] = weak / 256; /* right actuator? */
|
||||||
xpad->odata[5] = 0x00;
|
xpad->odata[5] = 0x00;
|
||||||
xpad->odata[6] = 0x00;
|
xpad->odata[6] = 0x00;
|
||||||
xpad->odata[7] = 0x00;
|
xpad->odata[7] = 0x00;
|
||||||
xpad->irq_out->transfer_buffer_length = 8;
|
xpad->irq_out->transfer_buffer_length = 8;
|
||||||
usb_submit_urb(xpad->irq_out, GFP_ATOMIC);
|
|
||||||
|
return usb_submit_urb(xpad->irq_out, GFP_ATOMIC);
|
||||||
|
|
||||||
|
default:
|
||||||
|
dbg("%s - rumble command sent to unsupported xpad type: %d",
|
||||||
|
__func__, xpad->xtype);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -579,7 +625,7 @@ static int xpad_play_effect(struct input_dev *dev, void *data,
|
||||||
|
|
||||||
static int xpad_init_ff(struct usb_xpad *xpad)
|
static int xpad_init_ff(struct usb_xpad *xpad)
|
||||||
{
|
{
|
||||||
if (xpad->xtype != XTYPE_XBOX360)
|
if (xpad->xtype != XTYPE_XBOX360 && xpad->xtype != XTYPE_XBOX)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
input_set_capability(xpad->dev, EV_FF, FF_RUMBLE);
|
input_set_capability(xpad->dev, EV_FF, FF_RUMBLE);
|
||||||
|
|
@ -712,11 +758,11 @@ static void xpad_set_up_abs(struct input_dev *input_dev, signed short abs)
|
||||||
input_set_abs_params(input_dev, abs, -32768, 32767, 16, 128);
|
input_set_abs_params(input_dev, abs, -32768, 32767, 16, 128);
|
||||||
break;
|
break;
|
||||||
case ABS_Z:
|
case ABS_Z:
|
||||||
case ABS_RZ: /* the triggers */
|
case ABS_RZ: /* the triggers (if mapped to axes) */
|
||||||
input_set_abs_params(input_dev, abs, 0, 255, 0, 0);
|
input_set_abs_params(input_dev, abs, 0, 255, 0, 0);
|
||||||
break;
|
break;
|
||||||
case ABS_HAT0X:
|
case ABS_HAT0X:
|
||||||
case ABS_HAT0Y: /* the d-pad (only if MAP_DPAD_TO_AXES) */
|
case ABS_HAT0Y: /* the d-pad (only if dpad is mapped to axes */
|
||||||
input_set_abs_params(input_dev, abs, -1, 1, 0, 0);
|
input_set_abs_params(input_dev, abs, -1, 1, 0, 0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -752,10 +798,9 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
|
||||||
goto fail2;
|
goto fail2;
|
||||||
|
|
||||||
xpad->udev = udev;
|
xpad->udev = udev;
|
||||||
xpad->dpad_mapping = xpad_device[i].dpad_mapping;
|
xpad->mapping = xpad_device[i].mapping;
|
||||||
xpad->xtype = xpad_device[i].xtype;
|
xpad->xtype = xpad_device[i].xtype;
|
||||||
if (xpad->dpad_mapping == MAP_DPAD_UNKNOWN)
|
|
||||||
xpad->dpad_mapping = !dpad_to_buttons;
|
|
||||||
if (xpad->xtype == XTYPE_UNKNOWN) {
|
if (xpad->xtype == XTYPE_UNKNOWN) {
|
||||||
if (intf->cur_altsetting->desc.bInterfaceClass == USB_CLASS_VENDOR_SPEC) {
|
if (intf->cur_altsetting->desc.bInterfaceClass == USB_CLASS_VENDOR_SPEC) {
|
||||||
if (intf->cur_altsetting->desc.bInterfaceProtocol == 129)
|
if (intf->cur_altsetting->desc.bInterfaceProtocol == 129)
|
||||||
|
|
@ -764,7 +809,13 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
|
||||||
xpad->xtype = XTYPE_XBOX360;
|
xpad->xtype = XTYPE_XBOX360;
|
||||||
} else
|
} else
|
||||||
xpad->xtype = XTYPE_XBOX;
|
xpad->xtype = XTYPE_XBOX;
|
||||||
|
|
||||||
|
if (dpad_to_buttons)
|
||||||
|
xpad->mapping |= MAP_DPAD_TO_BUTTONS;
|
||||||
|
if (triggers_to_buttons)
|
||||||
|
xpad->mapping |= MAP_TRIGGERS_TO_BUTTONS;
|
||||||
}
|
}
|
||||||
|
|
||||||
xpad->dev = input_dev;
|
xpad->dev = input_dev;
|
||||||
usb_make_path(udev, xpad->phys, sizeof(xpad->phys));
|
usb_make_path(udev, xpad->phys, sizeof(xpad->phys));
|
||||||
strlcat(xpad->phys, "/input0", sizeof(xpad->phys));
|
strlcat(xpad->phys, "/input0", sizeof(xpad->phys));
|
||||||
|
|
@ -781,25 +832,37 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
|
||||||
|
|
||||||
input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
|
input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
|
||||||
|
|
||||||
/* set up buttons */
|
/* set up standard buttons and axes */
|
||||||
for (i = 0; xpad_common_btn[i] >= 0; i++)
|
for (i = 0; xpad_common_btn[i] >= 0; i++)
|
||||||
set_bit(xpad_common_btn[i], input_dev->keybit);
|
__set_bit(xpad_common_btn[i], input_dev->keybit);
|
||||||
if ((xpad->xtype == XTYPE_XBOX360) || (xpad->xtype == XTYPE_XBOX360W))
|
|
||||||
for (i = 0; xpad360_btn[i] >= 0; i++)
|
|
||||||
set_bit(xpad360_btn[i], input_dev->keybit);
|
|
||||||
else
|
|
||||||
for (i = 0; xpad_btn[i] >= 0; i++)
|
|
||||||
set_bit(xpad_btn[i], input_dev->keybit);
|
|
||||||
if (xpad->dpad_mapping == MAP_DPAD_TO_BUTTONS)
|
|
||||||
for (i = 0; xpad_btn_pad[i] >= 0; i++)
|
|
||||||
set_bit(xpad_btn_pad[i], input_dev->keybit);
|
|
||||||
|
|
||||||
/* set up axes */
|
|
||||||
for (i = 0; xpad_abs[i] >= 0; i++)
|
for (i = 0; xpad_abs[i] >= 0; i++)
|
||||||
xpad_set_up_abs(input_dev, xpad_abs[i]);
|
xpad_set_up_abs(input_dev, xpad_abs[i]);
|
||||||
if (xpad->dpad_mapping == MAP_DPAD_TO_AXES)
|
|
||||||
|
/* Now set up model-specific ones */
|
||||||
|
if (xpad->xtype == XTYPE_XBOX360 || xpad->xtype == XTYPE_XBOX360W) {
|
||||||
|
for (i = 0; xpad360_btn[i] >= 0; i++)
|
||||||
|
__set_bit(xpad360_btn[i], input_dev->keybit);
|
||||||
|
} else {
|
||||||
|
for (i = 0; xpad_btn[i] >= 0; i++)
|
||||||
|
__set_bit(xpad_btn[i], input_dev->keybit);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (xpad->mapping & MAP_DPAD_TO_BUTTONS) {
|
||||||
|
for (i = 0; xpad_btn_pad[i] >= 0; i++)
|
||||||
|
__set_bit(xpad_btn_pad[i], input_dev->keybit);
|
||||||
|
} else {
|
||||||
for (i = 0; xpad_abs_pad[i] >= 0; i++)
|
for (i = 0; xpad_abs_pad[i] >= 0; i++)
|
||||||
xpad_set_up_abs(input_dev, xpad_abs_pad[i]);
|
xpad_set_up_abs(input_dev, xpad_abs_pad[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (xpad->mapping & MAP_TRIGGERS_TO_BUTTONS) {
|
||||||
|
for (i = 0; xpad_btn_triggers[i] >= 0; i++)
|
||||||
|
__set_bit(xpad_btn_triggers[i], input_dev->keybit);
|
||||||
|
} else {
|
||||||
|
for (i = 0; xpad_abs_triggers[i] >= 0; i++)
|
||||||
|
xpad_set_up_abs(input_dev, xpad_abs_triggers[i]);
|
||||||
|
}
|
||||||
|
|
||||||
error = xpad_init_output(intf, xpad);
|
error = xpad_init_output(intf, xpad);
|
||||||
if (error)
|
if (error)
|
||||||
|
|
|
||||||
|
|
@ -35,10 +35,10 @@ config KEYBOARD_ADP5520
|
||||||
be called adp5520-keys.
|
be called adp5520-keys.
|
||||||
|
|
||||||
config KEYBOARD_ADP5588
|
config KEYBOARD_ADP5588
|
||||||
tristate "ADP5588 I2C QWERTY Keypad and IO Expander"
|
tristate "ADP5588/87 I2C QWERTY Keypad and IO Expander"
|
||||||
depends on I2C
|
depends on I2C
|
||||||
help
|
help
|
||||||
Say Y here if you want to use a ADP5588 attached to your
|
Say Y here if you want to use a ADP5588/87 attached to your
|
||||||
system I2C bus.
|
system I2C bus.
|
||||||
|
|
||||||
To compile this driver as a module, choose M here: the
|
To compile this driver as a module, choose M here: the
|
||||||
|
|
@ -144,13 +144,15 @@ config KEYBOARD_BFIN
|
||||||
module will be called bf54x-keys.
|
module will be called bf54x-keys.
|
||||||
|
|
||||||
config KEYBOARD_CORGI
|
config KEYBOARD_CORGI
|
||||||
tristate "Corgi keyboard"
|
tristate "Corgi keyboard (deprecated)"
|
||||||
depends on PXA_SHARPSL
|
depends on PXA_SHARPSL
|
||||||
default y
|
|
||||||
help
|
help
|
||||||
Say Y here to enable the keyboard on the Sharp Zaurus SL-C7xx
|
Say Y here to enable the keyboard on the Sharp Zaurus SL-C7xx
|
||||||
series of PDAs.
|
series of PDAs.
|
||||||
|
|
||||||
|
This driver is now deprecated, use generic GPIO based matrix
|
||||||
|
keyboard driver instead.
|
||||||
|
|
||||||
To compile this driver as a module, choose M here: the
|
To compile this driver as a module, choose M here: the
|
||||||
module will be called corgikbd.
|
module will be called corgikbd.
|
||||||
|
|
||||||
|
|
@ -292,6 +294,15 @@ config KEYBOARD_MAX7359
|
||||||
To compile this driver as a module, choose M here: the
|
To compile this driver as a module, choose M here: the
|
||||||
module will be called max7359_keypad.
|
module will be called max7359_keypad.
|
||||||
|
|
||||||
|
config KEYBOARD_IMX
|
||||||
|
tristate "IMX keypad support"
|
||||||
|
depends on ARCH_MXC
|
||||||
|
help
|
||||||
|
Enable support for IMX keypad port.
|
||||||
|
|
||||||
|
To compile this driver as a module, choose M here: the
|
||||||
|
module will be called imx_keypad.
|
||||||
|
|
||||||
config KEYBOARD_NEWTON
|
config KEYBOARD_NEWTON
|
||||||
tristate "Newton keyboard"
|
tristate "Newton keyboard"
|
||||||
select SERIO
|
select SERIO
|
||||||
|
|
@ -329,13 +340,15 @@ config KEYBOARD_PXA930_ROTARY
|
||||||
module will be called pxa930_rotary.
|
module will be called pxa930_rotary.
|
||||||
|
|
||||||
config KEYBOARD_SPITZ
|
config KEYBOARD_SPITZ
|
||||||
tristate "Spitz keyboard"
|
tristate "Spitz keyboard (deprecated)"
|
||||||
depends on PXA_SHARPSL
|
depends on PXA_SHARPSL
|
||||||
default y
|
|
||||||
help
|
help
|
||||||
Say Y here to enable the keyboard on the Sharp Zaurus SL-C1000,
|
Say Y here to enable the keyboard on the Sharp Zaurus SL-C1000,
|
||||||
SL-C3000 and Sl-C3100 series of PDAs.
|
SL-C3000 and Sl-C3100 series of PDAs.
|
||||||
|
|
||||||
|
This driver is now deprecated, use generic GPIO based matrix
|
||||||
|
keyboard driver instead.
|
||||||
|
|
||||||
To compile this driver as a module, choose M here: the
|
To compile this driver as a module, choose M here: the
|
||||||
module will be called spitzkbd.
|
module will be called spitzkbd.
|
||||||
|
|
||||||
|
|
@ -363,7 +376,7 @@ config KEYBOARD_SUNKBD
|
||||||
|
|
||||||
config KEYBOARD_SH_KEYSC
|
config KEYBOARD_SH_KEYSC
|
||||||
tristate "SuperH KEYSC keypad support"
|
tristate "SuperH KEYSC keypad support"
|
||||||
depends on SUPERH
|
depends on SUPERH || ARCH_SHMOBILE
|
||||||
help
|
help
|
||||||
Say Y here if you want to use a keypad attached to the KEYSC block
|
Say Y here if you want to use a keypad attached to the KEYSC block
|
||||||
on SuperH processors such as sh7722 and sh7343.
|
on SuperH processors such as sh7722 and sh7343.
|
||||||
|
|
@ -402,12 +415,14 @@ config KEYBOARD_TWL4030
|
||||||
module will be called twl4030_keypad.
|
module will be called twl4030_keypad.
|
||||||
|
|
||||||
config KEYBOARD_TOSA
|
config KEYBOARD_TOSA
|
||||||
tristate "Tosa keyboard"
|
tristate "Tosa keyboard (deprecated)"
|
||||||
depends on MACH_TOSA
|
depends on MACH_TOSA
|
||||||
default y
|
|
||||||
help
|
help
|
||||||
Say Y here to enable the keyboard on the Sharp Zaurus SL-6000x (Tosa)
|
Say Y here to enable the keyboard on the Sharp Zaurus SL-6000x (Tosa)
|
||||||
|
|
||||||
|
This driver is now deprecated, use generic GPIO based matrix
|
||||||
|
keyboard driver instead.
|
||||||
|
|
||||||
To compile this driver as a module, choose M here: the
|
To compile this driver as a module, choose M here: the
|
||||||
module will be called tosakbd.
|
module will be called tosakbd.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ obj-$(CONFIG_KEYBOARD_EP93XX) += ep93xx_keypad.o
|
||||||
obj-$(CONFIG_KEYBOARD_GPIO) += gpio_keys.o
|
obj-$(CONFIG_KEYBOARD_GPIO) += gpio_keys.o
|
||||||
obj-$(CONFIG_KEYBOARD_HIL) += hil_kbd.o
|
obj-$(CONFIG_KEYBOARD_HIL) += hil_kbd.o
|
||||||
obj-$(CONFIG_KEYBOARD_HIL_OLD) += hilkbd.o
|
obj-$(CONFIG_KEYBOARD_HIL_OLD) += hilkbd.o
|
||||||
|
obj-$(CONFIG_KEYBOARD_IMX) += imx_keypad.o
|
||||||
obj-$(CONFIG_KEYBOARD_HP6XX) += jornada680_kbd.o
|
obj-$(CONFIG_KEYBOARD_HP6XX) += jornada680_kbd.o
|
||||||
obj-$(CONFIG_KEYBOARD_HP7XX) += jornada720_kbd.o
|
obj-$(CONFIG_KEYBOARD_HP7XX) += jornada720_kbd.o
|
||||||
obj-$(CONFIG_KEYBOARD_LKKBD) += lkkbd.o
|
obj-$(CONFIG_KEYBOARD_LKKBD) += lkkbd.o
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* File: drivers/input/keyboard/adp5588_keys.c
|
* File: drivers/input/keyboard/adp5588_keys.c
|
||||||
* Description: keypad driver for ADP5588 I2C QWERTY Keypad and IO Expander
|
* Description: keypad driver for ADP5588 and ADP5587
|
||||||
|
* I2C QWERTY Keypad and IO Expander
|
||||||
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||||
*
|
*
|
||||||
* Copyright (C) 2008-2009 Analog Devices Inc.
|
* Copyright (C) 2008-2009 Analog Devices Inc.
|
||||||
|
|
@ -327,6 +328,7 @@ static const struct dev_pm_ops adp5588_dev_pm_ops = {
|
||||||
|
|
||||||
static const struct i2c_device_id adp5588_id[] = {
|
static const struct i2c_device_id adp5588_id[] = {
|
||||||
{ KBUILD_MODNAME, 0 },
|
{ KBUILD_MODNAME, 0 },
|
||||||
|
{ "adp5587-keys", 0 },
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(i2c, adp5588_id);
|
MODULE_DEVICE_TABLE(i2c, adp5588_id);
|
||||||
|
|
@ -357,5 +359,5 @@ module_exit(adp5588_exit);
|
||||||
|
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
|
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
|
||||||
MODULE_DESCRIPTION("ADP5588 Keypad driver");
|
MODULE_DESCRIPTION("ADP5588/87 Keypad driver");
|
||||||
MODULE_ALIAS("platform:adp5588-keys");
|
MODULE_ALIAS("platform:adp5588-keys");
|
||||||
|
|
|
||||||
|
|
@ -40,26 +40,26 @@ module_param_named(set, atkbd_set, int, 0);
|
||||||
MODULE_PARM_DESC(set, "Select keyboard code set (2 = default, 3 = PS/2 native)");
|
MODULE_PARM_DESC(set, "Select keyboard code set (2 = default, 3 = PS/2 native)");
|
||||||
|
|
||||||
#if defined(__i386__) || defined(__x86_64__) || defined(__hppa__)
|
#if defined(__i386__) || defined(__x86_64__) || defined(__hppa__)
|
||||||
static int atkbd_reset;
|
static bool atkbd_reset;
|
||||||
#else
|
#else
|
||||||
static int atkbd_reset = 1;
|
static bool atkbd_reset = true;
|
||||||
#endif
|
#endif
|
||||||
module_param_named(reset, atkbd_reset, bool, 0);
|
module_param_named(reset, atkbd_reset, bool, 0);
|
||||||
MODULE_PARM_DESC(reset, "Reset keyboard during initialization");
|
MODULE_PARM_DESC(reset, "Reset keyboard during initialization");
|
||||||
|
|
||||||
static int atkbd_softrepeat;
|
static bool atkbd_softrepeat;
|
||||||
module_param_named(softrepeat, atkbd_softrepeat, bool, 0);
|
module_param_named(softrepeat, atkbd_softrepeat, bool, 0);
|
||||||
MODULE_PARM_DESC(softrepeat, "Use software keyboard repeat");
|
MODULE_PARM_DESC(softrepeat, "Use software keyboard repeat");
|
||||||
|
|
||||||
static int atkbd_softraw = 1;
|
static bool atkbd_softraw = true;
|
||||||
module_param_named(softraw, atkbd_softraw, bool, 0);
|
module_param_named(softraw, atkbd_softraw, bool, 0);
|
||||||
MODULE_PARM_DESC(softraw, "Use software generated rawmode");
|
MODULE_PARM_DESC(softraw, "Use software generated rawmode");
|
||||||
|
|
||||||
static int atkbd_scroll;
|
static bool atkbd_scroll;
|
||||||
module_param_named(scroll, atkbd_scroll, bool, 0);
|
module_param_named(scroll, atkbd_scroll, bool, 0);
|
||||||
MODULE_PARM_DESC(scroll, "Enable scroll-wheel on MS Office and similar keyboards");
|
MODULE_PARM_DESC(scroll, "Enable scroll-wheel on MS Office and similar keyboards");
|
||||||
|
|
||||||
static int atkbd_extra;
|
static bool atkbd_extra;
|
||||||
module_param_named(extra, atkbd_extra, bool, 0);
|
module_param_named(extra, atkbd_extra, bool, 0);
|
||||||
MODULE_PARM_DESC(extra, "Enable extra LEDs and keys on IBM RapidAcces, EzKey and similar keyboards");
|
MODULE_PARM_DESC(extra, "Enable extra LEDs and keys on IBM RapidAcces, EzKey and similar keyboards");
|
||||||
|
|
||||||
|
|
@ -156,13 +156,13 @@ static const unsigned short atkbd_unxlate_table[128] = {
|
||||||
#define ATKBD_KEY_UNKNOWN 0
|
#define ATKBD_KEY_UNKNOWN 0
|
||||||
#define ATKBD_KEY_NULL 255
|
#define ATKBD_KEY_NULL 255
|
||||||
|
|
||||||
#define ATKBD_SCR_1 254
|
#define ATKBD_SCR_1 0xfffe
|
||||||
#define ATKBD_SCR_2 253
|
#define ATKBD_SCR_2 0xfffd
|
||||||
#define ATKBD_SCR_4 252
|
#define ATKBD_SCR_4 0xfffc
|
||||||
#define ATKBD_SCR_8 251
|
#define ATKBD_SCR_8 0xfffb
|
||||||
#define ATKBD_SCR_CLICK 250
|
#define ATKBD_SCR_CLICK 0xfffa
|
||||||
#define ATKBD_SCR_LEFT 249
|
#define ATKBD_SCR_LEFT 0xfff9
|
||||||
#define ATKBD_SCR_RIGHT 248
|
#define ATKBD_SCR_RIGHT 0xfff8
|
||||||
|
|
||||||
#define ATKBD_SPECIAL ATKBD_SCR_RIGHT
|
#define ATKBD_SPECIAL ATKBD_SCR_RIGHT
|
||||||
|
|
||||||
|
|
@ -177,7 +177,7 @@ static const unsigned short atkbd_unxlate_table[128] = {
|
||||||
#define ATKBD_XL_HANJA 0x20
|
#define ATKBD_XL_HANJA 0x20
|
||||||
|
|
||||||
static const struct {
|
static const struct {
|
||||||
unsigned char keycode;
|
unsigned short keycode;
|
||||||
unsigned char set2;
|
unsigned char set2;
|
||||||
} atkbd_scroll_keys[] = {
|
} atkbd_scroll_keys[] = {
|
||||||
{ ATKBD_SCR_1, 0xc5 },
|
{ ATKBD_SCR_1, 0xc5 },
|
||||||
|
|
@ -206,18 +206,18 @@ struct atkbd {
|
||||||
unsigned short keycode[ATKBD_KEYMAP_SIZE];
|
unsigned short keycode[ATKBD_KEYMAP_SIZE];
|
||||||
DECLARE_BITMAP(force_release_mask, ATKBD_KEYMAP_SIZE);
|
DECLARE_BITMAP(force_release_mask, ATKBD_KEYMAP_SIZE);
|
||||||
unsigned char set;
|
unsigned char set;
|
||||||
unsigned char translated;
|
bool translated;
|
||||||
unsigned char extra;
|
bool extra;
|
||||||
unsigned char write;
|
bool write;
|
||||||
unsigned char softrepeat;
|
bool softrepeat;
|
||||||
unsigned char softraw;
|
bool softraw;
|
||||||
unsigned char scroll;
|
bool scroll;
|
||||||
unsigned char enabled;
|
bool enabled;
|
||||||
|
|
||||||
/* Accessed only from interrupt */
|
/* Accessed only from interrupt */
|
||||||
unsigned char emul;
|
unsigned char emul;
|
||||||
unsigned char resend;
|
bool resend;
|
||||||
unsigned char release;
|
bool release;
|
||||||
unsigned long xl_bit;
|
unsigned long xl_bit;
|
||||||
unsigned int last;
|
unsigned int last;
|
||||||
unsigned long time;
|
unsigned long time;
|
||||||
|
|
@ -301,18 +301,18 @@ static const unsigned int xl_table[] = {
|
||||||
* Checks if we should mangle the scancode to extract 'release' bit
|
* Checks if we should mangle the scancode to extract 'release' bit
|
||||||
* in translated mode.
|
* in translated mode.
|
||||||
*/
|
*/
|
||||||
static int atkbd_need_xlate(unsigned long xl_bit, unsigned char code)
|
static bool atkbd_need_xlate(unsigned long xl_bit, unsigned char code)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (code == ATKBD_RET_EMUL0 || code == ATKBD_RET_EMUL1)
|
if (code == ATKBD_RET_EMUL0 || code == ATKBD_RET_EMUL1)
|
||||||
return 0;
|
return false;
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(xl_table); i++)
|
for (i = 0; i < ARRAY_SIZE(xl_table); i++)
|
||||||
if (code == xl_table[i])
|
if (code == xl_table[i])
|
||||||
return test_bit(i, &xl_bit);
|
return test_bit(i, &xl_bit);
|
||||||
|
|
||||||
return 1;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -368,20 +368,18 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
|
||||||
int value;
|
int value;
|
||||||
unsigned short keycode;
|
unsigned short keycode;
|
||||||
|
|
||||||
#ifdef ATKBD_DEBUG
|
dev_dbg(&serio->dev, "Received %02x flags %02x\n", data, flags);
|
||||||
printk(KERN_DEBUG "atkbd.c: Received %02x flags %02x\n", data, flags);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if !defined(__i386__) && !defined (__x86_64__)
|
#if !defined(__i386__) && !defined (__x86_64__)
|
||||||
if ((flags & (SERIO_FRAME | SERIO_PARITY)) && (~flags & SERIO_TIMEOUT) && !atkbd->resend && atkbd->write) {
|
if ((flags & (SERIO_FRAME | SERIO_PARITY)) && (~flags & SERIO_TIMEOUT) && !atkbd->resend && atkbd->write) {
|
||||||
printk(KERN_WARNING "atkbd.c: frame/parity error: %02x\n", flags);
|
dev_warn(&serio->dev, "Frame/parity error: %02x\n", flags);
|
||||||
serio_write(serio, ATKBD_CMD_RESEND);
|
serio_write(serio, ATKBD_CMD_RESEND);
|
||||||
atkbd->resend = 1;
|
atkbd->resend = true;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!flags && data == ATKBD_RET_ACK)
|
if (!flags && data == ATKBD_RET_ACK)
|
||||||
atkbd->resend = 0;
|
atkbd->resend = false;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (unlikely(atkbd->ps2dev.flags & PS2_FLAG_ACK))
|
if (unlikely(atkbd->ps2dev.flags & PS2_FLAG_ACK))
|
||||||
|
|
@ -413,7 +411,7 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
|
||||||
|
|
||||||
switch (code) {
|
switch (code) {
|
||||||
case ATKBD_RET_BAT:
|
case ATKBD_RET_BAT:
|
||||||
atkbd->enabled = 0;
|
atkbd->enabled = false;
|
||||||
serio_reconnect(atkbd->ps2dev.serio);
|
serio_reconnect(atkbd->ps2dev.serio);
|
||||||
goto out;
|
goto out;
|
||||||
case ATKBD_RET_EMUL0:
|
case ATKBD_RET_EMUL0:
|
||||||
|
|
@ -423,20 +421,20 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
|
||||||
atkbd->emul = 2;
|
atkbd->emul = 2;
|
||||||
goto out;
|
goto out;
|
||||||
case ATKBD_RET_RELEASE:
|
case ATKBD_RET_RELEASE:
|
||||||
atkbd->release = 1;
|
atkbd->release = true;
|
||||||
goto out;
|
goto out;
|
||||||
case ATKBD_RET_ACK:
|
case ATKBD_RET_ACK:
|
||||||
case ATKBD_RET_NAK:
|
case ATKBD_RET_NAK:
|
||||||
if (printk_ratelimit())
|
if (printk_ratelimit())
|
||||||
printk(KERN_WARNING "atkbd.c: Spurious %s on %s. "
|
dev_warn(&serio->dev,
|
||||||
|
"Spurious %s on %s. "
|
||||||
"Some program might be trying access hardware directly.\n",
|
"Some program might be trying access hardware directly.\n",
|
||||||
data == ATKBD_RET_ACK ? "ACK" : "NAK", serio->phys);
|
data == ATKBD_RET_ACK ? "ACK" : "NAK", serio->phys);
|
||||||
goto out;
|
goto out;
|
||||||
case ATKBD_RET_ERR:
|
case ATKBD_RET_ERR:
|
||||||
atkbd->err_count++;
|
atkbd->err_count++;
|
||||||
#ifdef ATKBD_DEBUG
|
dev_dbg(&serio->dev, "Keyboard on %s reports too many keys pressed.\n",
|
||||||
printk(KERN_DEBUG "atkbd.c: Keyboard on %s reports too many keys pressed.\n", serio->phys);
|
serio->phys);
|
||||||
#endif
|
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -454,27 +452,27 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
|
||||||
case ATKBD_KEY_NULL:
|
case ATKBD_KEY_NULL:
|
||||||
break;
|
break;
|
||||||
case ATKBD_KEY_UNKNOWN:
|
case ATKBD_KEY_UNKNOWN:
|
||||||
printk(KERN_WARNING
|
dev_warn(&serio->dev,
|
||||||
"atkbd.c: Unknown key %s (%s set %d, code %#x on %s).\n",
|
"Unknown key %s (%s set %d, code %#x on %s).\n",
|
||||||
atkbd->release ? "released" : "pressed",
|
atkbd->release ? "released" : "pressed",
|
||||||
atkbd->translated ? "translated" : "raw",
|
atkbd->translated ? "translated" : "raw",
|
||||||
atkbd->set, code, serio->phys);
|
atkbd->set, code, serio->phys);
|
||||||
printk(KERN_WARNING
|
dev_warn(&serio->dev,
|
||||||
"atkbd.c: Use 'setkeycodes %s%02x <keycode>' to make it known.\n",
|
"Use 'setkeycodes %s%02x <keycode>' to make it known.\n",
|
||||||
code & 0x80 ? "e0" : "", code & 0x7f);
|
code & 0x80 ? "e0" : "", code & 0x7f);
|
||||||
input_sync(dev);
|
input_sync(dev);
|
||||||
break;
|
break;
|
||||||
case ATKBD_SCR_1:
|
case ATKBD_SCR_1:
|
||||||
scroll = 1 - atkbd->release * 2;
|
scroll = 1;
|
||||||
break;
|
break;
|
||||||
case ATKBD_SCR_2:
|
case ATKBD_SCR_2:
|
||||||
scroll = 2 - atkbd->release * 4;
|
scroll = 2;
|
||||||
break;
|
break;
|
||||||
case ATKBD_SCR_4:
|
case ATKBD_SCR_4:
|
||||||
scroll = 4 - atkbd->release * 8;
|
scroll = 4;
|
||||||
break;
|
break;
|
||||||
case ATKBD_SCR_8:
|
case ATKBD_SCR_8:
|
||||||
scroll = 8 - atkbd->release * 16;
|
scroll = 8;
|
||||||
break;
|
break;
|
||||||
case ATKBD_SCR_CLICK:
|
case ATKBD_SCR_CLICK:
|
||||||
click = !atkbd->release;
|
click = !atkbd->release;
|
||||||
|
|
@ -510,12 +508,13 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
|
||||||
if (atkbd->scroll) {
|
if (atkbd->scroll) {
|
||||||
if (click != -1)
|
if (click != -1)
|
||||||
input_report_key(dev, BTN_MIDDLE, click);
|
input_report_key(dev, BTN_MIDDLE, click);
|
||||||
input_report_rel(dev, REL_WHEEL, scroll);
|
input_report_rel(dev, REL_WHEEL,
|
||||||
|
atkbd->release ? -scroll : scroll);
|
||||||
input_report_rel(dev, REL_HWHEEL, hscroll);
|
input_report_rel(dev, REL_HWHEEL, hscroll);
|
||||||
input_sync(dev);
|
input_sync(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
atkbd->release = 0;
|
atkbd->release = false;
|
||||||
out:
|
out:
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
|
|
@ -642,9 +641,10 @@ static int atkbd_event(struct input_dev *dev,
|
||||||
if (!atkbd->softrepeat)
|
if (!atkbd->softrepeat)
|
||||||
atkbd_schedule_event_work(atkbd, ATKBD_REP_EVENT_BIT);
|
atkbd_schedule_event_work(atkbd, ATKBD_REP_EVENT_BIT);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
|
|
||||||
|
default:
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -655,7 +655,7 @@ static int atkbd_event(struct input_dev *dev,
|
||||||
static inline void atkbd_enable(struct atkbd *atkbd)
|
static inline void atkbd_enable(struct atkbd *atkbd)
|
||||||
{
|
{
|
||||||
serio_pause_rx(atkbd->ps2dev.serio);
|
serio_pause_rx(atkbd->ps2dev.serio);
|
||||||
atkbd->enabled = 1;
|
atkbd->enabled = true;
|
||||||
serio_continue_rx(atkbd->ps2dev.serio);
|
serio_continue_rx(atkbd->ps2dev.serio);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -667,7 +667,7 @@ static inline void atkbd_enable(struct atkbd *atkbd)
|
||||||
static inline void atkbd_disable(struct atkbd *atkbd)
|
static inline void atkbd_disable(struct atkbd *atkbd)
|
||||||
{
|
{
|
||||||
serio_pause_rx(atkbd->ps2dev.serio);
|
serio_pause_rx(atkbd->ps2dev.serio);
|
||||||
atkbd->enabled = 0;
|
atkbd->enabled = false;
|
||||||
serio_continue_rx(atkbd->ps2dev.serio);
|
serio_continue_rx(atkbd->ps2dev.serio);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -688,7 +688,9 @@ static int atkbd_probe(struct atkbd *atkbd)
|
||||||
|
|
||||||
if (atkbd_reset)
|
if (atkbd_reset)
|
||||||
if (ps2_command(ps2dev, NULL, ATKBD_CMD_RESET_BAT))
|
if (ps2_command(ps2dev, NULL, ATKBD_CMD_RESET_BAT))
|
||||||
printk(KERN_WARNING "atkbd.c: keyboard reset failed on %s\n", ps2dev->serio->phys);
|
dev_warn(&ps2dev->serio->dev,
|
||||||
|
"keyboard reset failed on %s\n",
|
||||||
|
ps2dev->serio->phys);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Then we check the keyboard ID. We should get 0xab83 under normal conditions.
|
* Then we check the keyboard ID. We should get 0xab83 under normal conditions.
|
||||||
|
|
@ -718,8 +720,9 @@ static int atkbd_probe(struct atkbd *atkbd)
|
||||||
atkbd->id = (param[0] << 8) | param[1];
|
atkbd->id = (param[0] << 8) | param[1];
|
||||||
|
|
||||||
if (atkbd->id == 0xaca1 && atkbd->translated) {
|
if (atkbd->id == 0xaca1 && atkbd->translated) {
|
||||||
printk(KERN_ERR "atkbd.c: NCD terminal keyboards are only supported on non-translating\n");
|
dev_err(&ps2dev->serio->dev,
|
||||||
printk(KERN_ERR "atkbd.c: controllers. Use i8042.direct=1 to disable translation.\n");
|
"NCD terminal keyboards are only supported on non-translating controlelrs. "
|
||||||
|
"Use i8042.direct=1 to disable translation.\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -737,7 +740,7 @@ static int atkbd_select_set(struct atkbd *atkbd, int target_set, int allow_extra
|
||||||
struct ps2dev *ps2dev = &atkbd->ps2dev;
|
struct ps2dev *ps2dev = &atkbd->ps2dev;
|
||||||
unsigned char param[2];
|
unsigned char param[2];
|
||||||
|
|
||||||
atkbd->extra = 0;
|
atkbd->extra = false;
|
||||||
/*
|
/*
|
||||||
* For known special keyboards we can go ahead and set the correct set.
|
* For known special keyboards we can go ahead and set the correct set.
|
||||||
* We check for NCD PS/2 Sun, NorthGate OmniKey 101 and
|
* We check for NCD PS/2 Sun, NorthGate OmniKey 101 and
|
||||||
|
|
@ -756,7 +759,7 @@ static int atkbd_select_set(struct atkbd *atkbd, int target_set, int allow_extra
|
||||||
if (allow_extra) {
|
if (allow_extra) {
|
||||||
param[0] = 0x71;
|
param[0] = 0x71;
|
||||||
if (!ps2_command(ps2dev, param, ATKBD_CMD_EX_ENABLE)) {
|
if (!ps2_command(ps2dev, param, ATKBD_CMD_EX_ENABLE)) {
|
||||||
atkbd->extra = 1;
|
atkbd->extra = true;
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -821,7 +824,8 @@ static int atkbd_activate(struct atkbd *atkbd)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (ps2_command(ps2dev, NULL, ATKBD_CMD_ENABLE)) {
|
if (ps2_command(ps2dev, NULL, ATKBD_CMD_ENABLE)) {
|
||||||
printk(KERN_ERR "atkbd.c: Failed to enable keyboard on %s\n",
|
dev_err(&ps2dev->serio->dev,
|
||||||
|
"Failed to enable keyboard on %s\n",
|
||||||
ps2dev->serio->phys);
|
ps2dev->serio->phys);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
@ -1070,9 +1074,13 @@ static void atkbd_set_device_attrs(struct atkbd *atkbd)
|
||||||
input_dev->keycodesize = sizeof(unsigned short);
|
input_dev->keycodesize = sizeof(unsigned short);
|
||||||
input_dev->keycodemax = ARRAY_SIZE(atkbd_set2_keycode);
|
input_dev->keycodemax = ARRAY_SIZE(atkbd_set2_keycode);
|
||||||
|
|
||||||
for (i = 0; i < ATKBD_KEYMAP_SIZE; i++)
|
for (i = 0; i < ATKBD_KEYMAP_SIZE; i++) {
|
||||||
if (atkbd->keycode[i] && atkbd->keycode[i] < ATKBD_SPECIAL)
|
if (atkbd->keycode[i] != KEY_RESERVED &&
|
||||||
|
atkbd->keycode[i] != ATKBD_KEY_NULL &&
|
||||||
|
atkbd->keycode[i] < ATKBD_SPECIAL) {
|
||||||
__set_bit(atkbd->keycode[i], input_dev->keybit);
|
__set_bit(atkbd->keycode[i], input_dev->keybit);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -1101,10 +1109,12 @@ static int atkbd_connect(struct serio *serio, struct serio_driver *drv)
|
||||||
switch (serio->id.type) {
|
switch (serio->id.type) {
|
||||||
|
|
||||||
case SERIO_8042_XL:
|
case SERIO_8042_XL:
|
||||||
atkbd->translated = 1;
|
atkbd->translated = true;
|
||||||
|
/* Fall through */
|
||||||
|
|
||||||
case SERIO_8042:
|
case SERIO_8042:
|
||||||
if (serio->write)
|
if (serio->write)
|
||||||
atkbd->write = 1;
|
atkbd->write = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1113,7 +1123,7 @@ static int atkbd_connect(struct serio *serio, struct serio_driver *drv)
|
||||||
atkbd->scroll = atkbd_scroll;
|
atkbd->scroll = atkbd_scroll;
|
||||||
|
|
||||||
if (atkbd->softrepeat)
|
if (atkbd->softrepeat)
|
||||||
atkbd->softraw = 1;
|
atkbd->softraw = true;
|
||||||
|
|
||||||
serio_set_drvdata(serio, atkbd);
|
serio_set_drvdata(serio, atkbd);
|
||||||
|
|
||||||
|
|
@ -1172,7 +1182,8 @@ static int atkbd_reconnect(struct serio *serio)
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
|
|
||||||
if (!atkbd || !drv) {
|
if (!atkbd || !drv) {
|
||||||
printk(KERN_DEBUG "atkbd: reconnect request, but serio is disconnected, ignoring...\n");
|
dev_dbg(&serio->dev,
|
||||||
|
"reconnect request, but serio is disconnected, ignoring...\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1286,7 +1297,8 @@ static ssize_t atkbd_set_extra(struct atkbd *atkbd, const char *buf, size_t coun
|
||||||
struct input_dev *old_dev, *new_dev;
|
struct input_dev *old_dev, *new_dev;
|
||||||
unsigned long value;
|
unsigned long value;
|
||||||
int err;
|
int err;
|
||||||
unsigned char old_extra, old_set;
|
bool old_extra;
|
||||||
|
unsigned char old_set;
|
||||||
|
|
||||||
if (!atkbd->write)
|
if (!atkbd->write)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
@ -1369,7 +1381,7 @@ static ssize_t atkbd_set_scroll(struct atkbd *atkbd, const char *buf, size_t cou
|
||||||
struct input_dev *old_dev, *new_dev;
|
struct input_dev *old_dev, *new_dev;
|
||||||
unsigned long value;
|
unsigned long value;
|
||||||
int err;
|
int err;
|
||||||
unsigned char old_scroll;
|
bool old_scroll;
|
||||||
|
|
||||||
if (strict_strtoul(buf, 10, &value) || value > 1)
|
if (strict_strtoul(buf, 10, &value) || value > 1)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
@ -1413,7 +1425,8 @@ static ssize_t atkbd_set_set(struct atkbd *atkbd, const char *buf, size_t count)
|
||||||
struct input_dev *old_dev, *new_dev;
|
struct input_dev *old_dev, *new_dev;
|
||||||
unsigned long value;
|
unsigned long value;
|
||||||
int err;
|
int err;
|
||||||
unsigned char old_set, old_extra;
|
unsigned char old_set;
|
||||||
|
bool old_extra;
|
||||||
|
|
||||||
if (!atkbd->write)
|
if (!atkbd->write)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
@ -1463,7 +1476,7 @@ static ssize_t atkbd_set_softrepeat(struct atkbd *atkbd, const char *buf, size_t
|
||||||
struct input_dev *old_dev, *new_dev;
|
struct input_dev *old_dev, *new_dev;
|
||||||
unsigned long value;
|
unsigned long value;
|
||||||
int err;
|
int err;
|
||||||
unsigned char old_softrepeat, old_softraw;
|
bool old_softrepeat, old_softraw;
|
||||||
|
|
||||||
if (!atkbd->write)
|
if (!atkbd->write)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
@ -1483,7 +1496,7 @@ static ssize_t atkbd_set_softrepeat(struct atkbd *atkbd, const char *buf, size_t
|
||||||
atkbd->dev = new_dev;
|
atkbd->dev = new_dev;
|
||||||
atkbd->softrepeat = value;
|
atkbd->softrepeat = value;
|
||||||
if (atkbd->softrepeat)
|
if (atkbd->softrepeat)
|
||||||
atkbd->softraw = 1;
|
atkbd->softraw = true;
|
||||||
atkbd_set_device_attrs(atkbd);
|
atkbd_set_device_attrs(atkbd);
|
||||||
|
|
||||||
err = input_register_device(atkbd->dev);
|
err = input_register_device(atkbd->dev);
|
||||||
|
|
@ -1513,7 +1526,7 @@ static ssize_t atkbd_set_softraw(struct atkbd *atkbd, const char *buf, size_t co
|
||||||
struct input_dev *old_dev, *new_dev;
|
struct input_dev *old_dev, *new_dev;
|
||||||
unsigned long value;
|
unsigned long value;
|
||||||
int err;
|
int err;
|
||||||
unsigned char old_softraw;
|
bool old_softraw;
|
||||||
|
|
||||||
if (strict_strtoul(buf, 10, &value) || value > 1)
|
if (strict_strtoul(buf, 10, &value) || value > 1)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
|
||||||
|
|
@ -69,7 +69,7 @@ struct ep93xx_keypad {
|
||||||
|
|
||||||
void __iomem *mmio_base;
|
void __iomem *mmio_base;
|
||||||
|
|
||||||
unsigned int matrix_keycodes[EP93XX_MATRIX_SIZE];
|
unsigned short keycodes[EP93XX_MATRIX_SIZE];
|
||||||
|
|
||||||
int key1;
|
int key1;
|
||||||
int key2;
|
int key2;
|
||||||
|
|
@ -79,24 +79,6 @@ struct ep93xx_keypad {
|
||||||
bool enabled;
|
bool enabled;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void ep93xx_keypad_build_keycode(struct ep93xx_keypad *keypad)
|
|
||||||
{
|
|
||||||
struct ep93xx_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_ROW(*key);
|
|
||||||
int col = KEY_COL(*key);
|
|
||||||
int code = KEY_VAL(*key);
|
|
||||||
|
|
||||||
keypad->matrix_keycodes[(row << 3) + col] = code;
|
|
||||||
__set_bit(code, input_dev->keybit);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static irqreturn_t ep93xx_keypad_irq_handler(int irq, void *dev_id)
|
static irqreturn_t ep93xx_keypad_irq_handler(int irq, void *dev_id)
|
||||||
{
|
{
|
||||||
struct ep93xx_keypad *keypad = dev_id;
|
struct ep93xx_keypad *keypad = dev_id;
|
||||||
|
|
@ -107,10 +89,10 @@ static irqreturn_t ep93xx_keypad_irq_handler(int irq, void *dev_id)
|
||||||
status = __raw_readl(keypad->mmio_base + KEY_REG);
|
status = __raw_readl(keypad->mmio_base + KEY_REG);
|
||||||
|
|
||||||
keycode = (status & KEY_REG_KEY1_MASK) >> KEY_REG_KEY1_SHIFT;
|
keycode = (status & KEY_REG_KEY1_MASK) >> KEY_REG_KEY1_SHIFT;
|
||||||
key1 = keypad->matrix_keycodes[keycode];
|
key1 = keypad->keycodes[keycode];
|
||||||
|
|
||||||
keycode = (status & KEY_REG_KEY2_MASK) >> KEY_REG_KEY2_SHIFT;
|
keycode = (status & KEY_REG_KEY2_MASK) >> KEY_REG_KEY2_SHIFT;
|
||||||
key2 = keypad->matrix_keycodes[keycode];
|
key2 = keypad->keycodes[keycode];
|
||||||
|
|
||||||
if (status & KEY_REG_2KEYS) {
|
if (status & KEY_REG_2KEYS) {
|
||||||
if (keypad->key1 && key1 != keypad->key1 && key2 != keypad->key1)
|
if (keypad->key1 && key1 != keypad->key1 && key2 != keypad->key1)
|
||||||
|
|
@ -256,6 +238,7 @@ static int ep93xx_keypad_resume(struct platform_device *pdev)
|
||||||
static int __devinit ep93xx_keypad_probe(struct platform_device *pdev)
|
static int __devinit ep93xx_keypad_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct ep93xx_keypad *keypad;
|
struct ep93xx_keypad *keypad;
|
||||||
|
const struct matrix_keymap_data *keymap_data;
|
||||||
struct input_dev *input_dev;
|
struct input_dev *input_dev;
|
||||||
struct resource *res;
|
struct resource *res;
|
||||||
int err;
|
int err;
|
||||||
|
|
@ -270,6 +253,12 @@ static int __devinit ep93xx_keypad_probe(struct platform_device *pdev)
|
||||||
goto failed_free;
|
goto failed_free;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
keymap_data = keypad->pdata->keymap_data;
|
||||||
|
if (!keymap_data) {
|
||||||
|
err = -EINVAL;
|
||||||
|
goto failed_free;
|
||||||
|
}
|
||||||
|
|
||||||
keypad->irq = platform_get_irq(pdev, 0);
|
keypad->irq = platform_get_irq(pdev, 0);
|
||||||
if (!keypad->irq) {
|
if (!keypad->irq) {
|
||||||
err = -ENXIO;
|
err = -ENXIO;
|
||||||
|
|
@ -317,9 +306,9 @@ static int __devinit ep93xx_keypad_probe(struct platform_device *pdev)
|
||||||
input_dev->open = ep93xx_keypad_open;
|
input_dev->open = ep93xx_keypad_open;
|
||||||
input_dev->close = ep93xx_keypad_close;
|
input_dev->close = ep93xx_keypad_close;
|
||||||
input_dev->dev.parent = &pdev->dev;
|
input_dev->dev.parent = &pdev->dev;
|
||||||
input_dev->keycode = keypad->matrix_keycodes;
|
input_dev->keycode = keypad->keycodes;
|
||||||
input_dev->keycodesize = sizeof(keypad->matrix_keycodes[0]);
|
input_dev->keycodesize = sizeof(keypad->keycodes[0]);
|
||||||
input_dev->keycodemax = ARRAY_SIZE(keypad->matrix_keycodes);
|
input_dev->keycodemax = ARRAY_SIZE(keypad->keycodes);
|
||||||
|
|
||||||
input_set_drvdata(input_dev, keypad);
|
input_set_drvdata(input_dev, keypad);
|
||||||
|
|
||||||
|
|
@ -327,7 +316,8 @@ static int __devinit ep93xx_keypad_probe(struct platform_device *pdev)
|
||||||
if (keypad->pdata->flags & EP93XX_KEYPAD_AUTOREPEAT)
|
if (keypad->pdata->flags & EP93XX_KEYPAD_AUTOREPEAT)
|
||||||
input_dev->evbit[0] |= BIT_MASK(EV_REP);
|
input_dev->evbit[0] |= BIT_MASK(EV_REP);
|
||||||
|
|
||||||
ep93xx_keypad_build_keycode(keypad);
|
matrix_keypad_build_keymap(keymap_data, 3,
|
||||||
|
input_dev->keycode, input_dev->keybit);
|
||||||
platform_set_drvdata(pdev, keypad);
|
platform_set_drvdata(pdev, keypad);
|
||||||
|
|
||||||
err = request_irq(keypad->irq, ep93xx_keypad_irq_handler,
|
err = request_irq(keypad->irq, ep93xx_keypad_irq_handler,
|
||||||
|
|
|
||||||
|
|
@ -30,13 +30,289 @@ struct gpio_button_data {
|
||||||
struct input_dev *input;
|
struct input_dev *input;
|
||||||
struct timer_list timer;
|
struct timer_list timer;
|
||||||
struct work_struct work;
|
struct work_struct work;
|
||||||
|
bool disabled;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct gpio_keys_drvdata {
|
struct gpio_keys_drvdata {
|
||||||
struct input_dev *input;
|
struct input_dev *input;
|
||||||
|
struct mutex disable_lock;
|
||||||
|
unsigned int n_buttons;
|
||||||
struct gpio_button_data data[0];
|
struct gpio_button_data data[0];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SYSFS interface for enabling/disabling keys and switches:
|
||||||
|
*
|
||||||
|
* There are 4 attributes under /sys/devices/platform/gpio-keys/
|
||||||
|
* keys [ro] - bitmap of keys (EV_KEY) which can be
|
||||||
|
* disabled
|
||||||
|
* switches [ro] - bitmap of switches (EV_SW) which can be
|
||||||
|
* disabled
|
||||||
|
* disabled_keys [rw] - bitmap of keys currently disabled
|
||||||
|
* disabled_switches [rw] - bitmap of switches currently disabled
|
||||||
|
*
|
||||||
|
* Userland can change these values and hence disable event generation
|
||||||
|
* for each key (or switch). Disabling a key means its interrupt line
|
||||||
|
* is disabled.
|
||||||
|
*
|
||||||
|
* For example, if we have following switches set up as gpio-keys:
|
||||||
|
* SW_DOCK = 5
|
||||||
|
* SW_CAMERA_LENS_COVER = 9
|
||||||
|
* SW_KEYPAD_SLIDE = 10
|
||||||
|
* SW_FRONT_PROXIMITY = 11
|
||||||
|
* This is read from switches:
|
||||||
|
* 11-9,5
|
||||||
|
* Next we want to disable proximity (11) and dock (5), we write:
|
||||||
|
* 11,5
|
||||||
|
* to file disabled_switches. Now proximity and dock IRQs are disabled.
|
||||||
|
* This can be verified by reading the file disabled_switches:
|
||||||
|
* 11,5
|
||||||
|
* If we now want to enable proximity (11) switch we write:
|
||||||
|
* 5
|
||||||
|
* to disabled_switches.
|
||||||
|
*
|
||||||
|
* We can disable only those keys which don't allow sharing the irq.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get_n_events_by_type() - returns maximum number of events per @type
|
||||||
|
* @type: type of button (%EV_KEY, %EV_SW)
|
||||||
|
*
|
||||||
|
* Return value of this function can be used to allocate bitmap
|
||||||
|
* large enough to hold all bits for given type.
|
||||||
|
*/
|
||||||
|
static inline int get_n_events_by_type(int type)
|
||||||
|
{
|
||||||
|
BUG_ON(type != EV_SW && type != EV_KEY);
|
||||||
|
|
||||||
|
return (type == EV_KEY) ? KEY_CNT : SW_CNT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gpio_keys_disable_button() - disables given GPIO button
|
||||||
|
* @bdata: button data for button to be disabled
|
||||||
|
*
|
||||||
|
* Disables button pointed by @bdata. This is done by masking
|
||||||
|
* IRQ line. After this function is called, button won't generate
|
||||||
|
* input events anymore. Note that one can only disable buttons
|
||||||
|
* that don't share IRQs.
|
||||||
|
*
|
||||||
|
* Make sure that @bdata->disable_lock is locked when entering
|
||||||
|
* this function to avoid races when concurrent threads are
|
||||||
|
* disabling buttons at the same time.
|
||||||
|
*/
|
||||||
|
static void gpio_keys_disable_button(struct gpio_button_data *bdata)
|
||||||
|
{
|
||||||
|
if (!bdata->disabled) {
|
||||||
|
/*
|
||||||
|
* Disable IRQ and possible debouncing timer.
|
||||||
|
*/
|
||||||
|
disable_irq(gpio_to_irq(bdata->button->gpio));
|
||||||
|
if (bdata->button->debounce_interval)
|
||||||
|
del_timer_sync(&bdata->timer);
|
||||||
|
|
||||||
|
bdata->disabled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gpio_keys_enable_button() - enables given GPIO button
|
||||||
|
* @bdata: button data for button to be disabled
|
||||||
|
*
|
||||||
|
* Enables given button pointed by @bdata.
|
||||||
|
*
|
||||||
|
* Make sure that @bdata->disable_lock is locked when entering
|
||||||
|
* this function to avoid races with concurrent threads trying
|
||||||
|
* to enable the same button at the same time.
|
||||||
|
*/
|
||||||
|
static void gpio_keys_enable_button(struct gpio_button_data *bdata)
|
||||||
|
{
|
||||||
|
if (bdata->disabled) {
|
||||||
|
enable_irq(gpio_to_irq(bdata->button->gpio));
|
||||||
|
bdata->disabled = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gpio_keys_attr_show_helper() - fill in stringified bitmap of buttons
|
||||||
|
* @ddata: pointer to drvdata
|
||||||
|
* @buf: buffer where stringified bitmap is written
|
||||||
|
* @type: button type (%EV_KEY, %EV_SW)
|
||||||
|
* @only_disabled: does caller want only those buttons that are
|
||||||
|
* currently disabled or all buttons that can be
|
||||||
|
* disabled
|
||||||
|
*
|
||||||
|
* This function writes buttons that can be disabled to @buf. If
|
||||||
|
* @only_disabled is true, then @buf contains only those buttons
|
||||||
|
* that are currently disabled. Returns 0 on success or negative
|
||||||
|
* errno on failure.
|
||||||
|
*/
|
||||||
|
static ssize_t gpio_keys_attr_show_helper(struct gpio_keys_drvdata *ddata,
|
||||||
|
char *buf, unsigned int type,
|
||||||
|
bool only_disabled)
|
||||||
|
{
|
||||||
|
int n_events = get_n_events_by_type(type);
|
||||||
|
unsigned long *bits;
|
||||||
|
ssize_t ret;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
bits = kcalloc(BITS_TO_LONGS(n_events), sizeof(*bits), GFP_KERNEL);
|
||||||
|
if (!bits)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
for (i = 0; i < ddata->n_buttons; i++) {
|
||||||
|
struct gpio_button_data *bdata = &ddata->data[i];
|
||||||
|
|
||||||
|
if (bdata->button->type != type)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (only_disabled && !bdata->disabled)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
__set_bit(bdata->button->code, bits);
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = bitmap_scnlistprintf(buf, PAGE_SIZE - 2, bits, n_events);
|
||||||
|
buf[ret++] = '\n';
|
||||||
|
buf[ret] = '\0';
|
||||||
|
|
||||||
|
kfree(bits);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gpio_keys_attr_store_helper() - enable/disable buttons based on given bitmap
|
||||||
|
* @ddata: pointer to drvdata
|
||||||
|
* @buf: buffer from userspace that contains stringified bitmap
|
||||||
|
* @type: button type (%EV_KEY, %EV_SW)
|
||||||
|
*
|
||||||
|
* This function parses stringified bitmap from @buf and disables/enables
|
||||||
|
* GPIO buttons accordinly. Returns 0 on success and negative error
|
||||||
|
* on failure.
|
||||||
|
*/
|
||||||
|
static ssize_t gpio_keys_attr_store_helper(struct gpio_keys_drvdata *ddata,
|
||||||
|
const char *buf, unsigned int type)
|
||||||
|
{
|
||||||
|
int n_events = get_n_events_by_type(type);
|
||||||
|
unsigned long *bits;
|
||||||
|
ssize_t error;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
bits = kcalloc(BITS_TO_LONGS(n_events), sizeof(*bits), GFP_KERNEL);
|
||||||
|
if (!bits)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
error = bitmap_parselist(buf, bits, n_events);
|
||||||
|
if (error)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
/* First validate */
|
||||||
|
for (i = 0; i < ddata->n_buttons; i++) {
|
||||||
|
struct gpio_button_data *bdata = &ddata->data[i];
|
||||||
|
|
||||||
|
if (bdata->button->type != type)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (test_bit(bdata->button->code, bits) &&
|
||||||
|
!bdata->button->can_disable) {
|
||||||
|
error = -EINVAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex_lock(&ddata->disable_lock);
|
||||||
|
|
||||||
|
for (i = 0; i < ddata->n_buttons; i++) {
|
||||||
|
struct gpio_button_data *bdata = &ddata->data[i];
|
||||||
|
|
||||||
|
if (bdata->button->type != type)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (test_bit(bdata->button->code, bits))
|
||||||
|
gpio_keys_disable_button(bdata);
|
||||||
|
else
|
||||||
|
gpio_keys_enable_button(bdata);
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex_unlock(&ddata->disable_lock);
|
||||||
|
|
||||||
|
out:
|
||||||
|
kfree(bits);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define ATTR_SHOW_FN(name, type, only_disabled) \
|
||||||
|
static ssize_t gpio_keys_show_##name(struct device *dev, \
|
||||||
|
struct device_attribute *attr, \
|
||||||
|
char *buf) \
|
||||||
|
{ \
|
||||||
|
struct platform_device *pdev = to_platform_device(dev); \
|
||||||
|
struct gpio_keys_drvdata *ddata = platform_get_drvdata(pdev); \
|
||||||
|
\
|
||||||
|
return gpio_keys_attr_show_helper(ddata, buf, \
|
||||||
|
type, only_disabled); \
|
||||||
|
}
|
||||||
|
|
||||||
|
ATTR_SHOW_FN(keys, EV_KEY, false);
|
||||||
|
ATTR_SHOW_FN(switches, EV_SW, false);
|
||||||
|
ATTR_SHOW_FN(disabled_keys, EV_KEY, true);
|
||||||
|
ATTR_SHOW_FN(disabled_switches, EV_SW, true);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ATTRIBUTES:
|
||||||
|
*
|
||||||
|
* /sys/devices/platform/gpio-keys/keys [ro]
|
||||||
|
* /sys/devices/platform/gpio-keys/switches [ro]
|
||||||
|
*/
|
||||||
|
static DEVICE_ATTR(keys, S_IRUGO, gpio_keys_show_keys, NULL);
|
||||||
|
static DEVICE_ATTR(switches, S_IRUGO, gpio_keys_show_switches, NULL);
|
||||||
|
|
||||||
|
#define ATTR_STORE_FN(name, type) \
|
||||||
|
static ssize_t gpio_keys_store_##name(struct device *dev, \
|
||||||
|
struct device_attribute *attr, \
|
||||||
|
const char *buf, \
|
||||||
|
size_t count) \
|
||||||
|
{ \
|
||||||
|
struct platform_device *pdev = to_platform_device(dev); \
|
||||||
|
struct gpio_keys_drvdata *ddata = platform_get_drvdata(pdev); \
|
||||||
|
ssize_t error; \
|
||||||
|
\
|
||||||
|
error = gpio_keys_attr_store_helper(ddata, buf, type); \
|
||||||
|
if (error) \
|
||||||
|
return error; \
|
||||||
|
\
|
||||||
|
return count; \
|
||||||
|
}
|
||||||
|
|
||||||
|
ATTR_STORE_FN(disabled_keys, EV_KEY);
|
||||||
|
ATTR_STORE_FN(disabled_switches, EV_SW);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ATTRIBUTES:
|
||||||
|
*
|
||||||
|
* /sys/devices/platform/gpio-keys/disabled_keys [rw]
|
||||||
|
* /sys/devices/platform/gpio-keys/disables_switches [rw]
|
||||||
|
*/
|
||||||
|
static DEVICE_ATTR(disabled_keys, S_IWUSR | S_IRUGO,
|
||||||
|
gpio_keys_show_disabled_keys,
|
||||||
|
gpio_keys_store_disabled_keys);
|
||||||
|
static DEVICE_ATTR(disabled_switches, S_IWUSR | S_IRUGO,
|
||||||
|
gpio_keys_show_disabled_switches,
|
||||||
|
gpio_keys_store_disabled_switches);
|
||||||
|
|
||||||
|
static struct attribute *gpio_keys_attrs[] = {
|
||||||
|
&dev_attr_keys.attr,
|
||||||
|
&dev_attr_switches.attr,
|
||||||
|
&dev_attr_disabled_keys.attr,
|
||||||
|
&dev_attr_disabled_switches.attr,
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct attribute_group gpio_keys_attr_group = {
|
||||||
|
.attrs = gpio_keys_attrs,
|
||||||
|
};
|
||||||
|
|
||||||
static void gpio_keys_report_event(struct gpio_button_data *bdata)
|
static void gpio_keys_report_event(struct gpio_button_data *bdata)
|
||||||
{
|
{
|
||||||
struct gpio_keys_button *button = bdata->button;
|
struct gpio_keys_button *button = bdata->button;
|
||||||
|
|
@ -79,11 +355,13 @@ static irqreturn_t gpio_keys_isr(int irq, void *dev_id)
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __devinit gpio_keys_setup_key(struct device *dev,
|
static int __devinit gpio_keys_setup_key(struct platform_device *pdev,
|
||||||
struct gpio_button_data *bdata,
|
struct gpio_button_data *bdata,
|
||||||
struct gpio_keys_button *button)
|
struct gpio_keys_button *button)
|
||||||
{
|
{
|
||||||
char *desc = button->desc ? button->desc : "gpio_keys";
|
char *desc = button->desc ? button->desc : "gpio_keys";
|
||||||
|
struct device *dev = &pdev->dev;
|
||||||
|
unsigned long irqflags;
|
||||||
int irq, error;
|
int irq, error;
|
||||||
|
|
||||||
setup_timer(&bdata->timer, gpio_keys_timer, (unsigned long)bdata);
|
setup_timer(&bdata->timer, gpio_keys_timer, (unsigned long)bdata);
|
||||||
|
|
@ -112,10 +390,15 @@ static int __devinit gpio_keys_setup_key(struct device *dev,
|
||||||
goto fail3;
|
goto fail3;
|
||||||
}
|
}
|
||||||
|
|
||||||
error = request_irq(irq, gpio_keys_isr,
|
irqflags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING;
|
||||||
IRQF_SHARED |
|
/*
|
||||||
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
|
* If platform has specified that the button can be disabled,
|
||||||
desc, bdata);
|
* we don't want it to share the interrupt line.
|
||||||
|
*/
|
||||||
|
if (!button->can_disable)
|
||||||
|
irqflags |= IRQF_SHARED;
|
||||||
|
|
||||||
|
error = request_irq(irq, gpio_keys_isr, irqflags, desc, bdata);
|
||||||
if (error) {
|
if (error) {
|
||||||
dev_err(dev, "Unable to claim irq %d; error %d\n",
|
dev_err(dev, "Unable to claim irq %d; error %d\n",
|
||||||
irq, error);
|
irq, error);
|
||||||
|
|
@ -149,6 +432,10 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
|
||||||
goto fail1;
|
goto fail1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ddata->input = input;
|
||||||
|
ddata->n_buttons = pdata->nbuttons;
|
||||||
|
mutex_init(&ddata->disable_lock);
|
||||||
|
|
||||||
platform_set_drvdata(pdev, ddata);
|
platform_set_drvdata(pdev, ddata);
|
||||||
|
|
||||||
input->name = pdev->name;
|
input->name = pdev->name;
|
||||||
|
|
@ -164,8 +451,6 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
|
||||||
if (pdata->rep)
|
if (pdata->rep)
|
||||||
__set_bit(EV_REP, input->evbit);
|
__set_bit(EV_REP, input->evbit);
|
||||||
|
|
||||||
ddata->input = input;
|
|
||||||
|
|
||||||
for (i = 0; i < pdata->nbuttons; i++) {
|
for (i = 0; i < pdata->nbuttons; i++) {
|
||||||
struct gpio_keys_button *button = &pdata->buttons[i];
|
struct gpio_keys_button *button = &pdata->buttons[i];
|
||||||
struct gpio_button_data *bdata = &ddata->data[i];
|
struct gpio_button_data *bdata = &ddata->data[i];
|
||||||
|
|
@ -174,7 +459,7 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
|
||||||
bdata->input = input;
|
bdata->input = input;
|
||||||
bdata->button = button;
|
bdata->button = button;
|
||||||
|
|
||||||
error = gpio_keys_setup_key(dev, bdata, button);
|
error = gpio_keys_setup_key(pdev, bdata, button);
|
||||||
if (error)
|
if (error)
|
||||||
goto fail2;
|
goto fail2;
|
||||||
|
|
||||||
|
|
@ -184,11 +469,18 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
|
||||||
input_set_capability(input, type, button->code);
|
input_set_capability(input, type, button->code);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
error = sysfs_create_group(&pdev->dev.kobj, &gpio_keys_attr_group);
|
||||||
|
if (error) {
|
||||||
|
dev_err(dev, "Unable to export keys/switches, error: %d\n",
|
||||||
|
error);
|
||||||
|
goto fail2;
|
||||||
|
}
|
||||||
|
|
||||||
error = input_register_device(input);
|
error = input_register_device(input);
|
||||||
if (error) {
|
if (error) {
|
||||||
dev_err(dev, "Unable to register input device, "
|
dev_err(dev, "Unable to register input device, error: %d\n",
|
||||||
"error: %d\n", error);
|
error);
|
||||||
goto fail2;
|
goto fail3;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* get current state of buttons */
|
/* get current state of buttons */
|
||||||
|
|
@ -200,6 +492,8 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
fail3:
|
||||||
|
sysfs_remove_group(&pdev->dev.kobj, &gpio_keys_attr_group);
|
||||||
fail2:
|
fail2:
|
||||||
while (--i >= 0) {
|
while (--i >= 0) {
|
||||||
free_irq(gpio_to_irq(pdata->buttons[i].gpio), &ddata->data[i]);
|
free_irq(gpio_to_irq(pdata->buttons[i].gpio), &ddata->data[i]);
|
||||||
|
|
@ -224,6 +518,8 @@ static int __devexit gpio_keys_remove(struct platform_device *pdev)
|
||||||
struct input_dev *input = ddata->input;
|
struct input_dev *input = ddata->input;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
sysfs_remove_group(&pdev->dev.kobj, &gpio_keys_attr_group);
|
||||||
|
|
||||||
device_init_wakeup(&pdev->dev, 0);
|
device_init_wakeup(&pdev->dev, 0);
|
||||||
|
|
||||||
for (i = 0; i < pdata->nbuttons; i++) {
|
for (i = 0; i < pdata->nbuttons; i++) {
|
||||||
|
|
|
||||||
594
drivers/input/keyboard/imx_keypad.c
Normal file
594
drivers/input/keyboard/imx_keypad.c
Normal file
|
|
@ -0,0 +1,594 @@
|
||||||
|
/*
|
||||||
|
* Driver for the IMX keypad port.
|
||||||
|
* Copyright (C) 2009 Alberto Panizzo <maramaopercheseimorto@gmail.com>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* <<Power management needs to be implemented>>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/clk.h>
|
||||||
|
#include <linux/delay.h>
|
||||||
|
#include <linux/device.h>
|
||||||
|
#include <linux/err.h>
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/input/matrix_keypad.h>
|
||||||
|
#include <linux/interrupt.h>
|
||||||
|
#include <linux/io.h>
|
||||||
|
#include <linux/jiffies.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/timer.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Keypad Controller registers (halfword)
|
||||||
|
*/
|
||||||
|
#define KPCR 0x00 /* Keypad Control Register */
|
||||||
|
|
||||||
|
#define KPSR 0x02 /* Keypad Status Register */
|
||||||
|
#define KBD_STAT_KPKD (0x1 << 0) /* Key Press Interrupt Status bit (w1c) */
|
||||||
|
#define KBD_STAT_KPKR (0x1 << 1) /* Key Release Interrupt Status bit (w1c) */
|
||||||
|
#define KBD_STAT_KDSC (0x1 << 2) /* Key Depress Synch Chain Status bit (w1c)*/
|
||||||
|
#define KBD_STAT_KRSS (0x1 << 3) /* Key Release Synch Status bit (w1c)*/
|
||||||
|
#define KBD_STAT_KDIE (0x1 << 8) /* Key Depress Interrupt Enable Status bit */
|
||||||
|
#define KBD_STAT_KRIE (0x1 << 9) /* Key Release Interrupt Enable */
|
||||||
|
#define KBD_STAT_KPPEN (0x1 << 10) /* Keypad Clock Enable */
|
||||||
|
|
||||||
|
#define KDDR 0x04 /* Keypad Data Direction Register */
|
||||||
|
#define KPDR 0x06 /* Keypad Data Register */
|
||||||
|
|
||||||
|
#define MAX_MATRIX_KEY_ROWS 8
|
||||||
|
#define MAX_MATRIX_KEY_COLS 8
|
||||||
|
#define MATRIX_ROW_SHIFT 3
|
||||||
|
|
||||||
|
#define MAX_MATRIX_KEY_NUM (MAX_MATRIX_KEY_ROWS * MAX_MATRIX_KEY_COLS)
|
||||||
|
|
||||||
|
struct imx_keypad {
|
||||||
|
|
||||||
|
struct clk *clk;
|
||||||
|
struct input_dev *input_dev;
|
||||||
|
void __iomem *mmio_base;
|
||||||
|
|
||||||
|
int irq;
|
||||||
|
struct timer_list check_matrix_timer;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The matrix is stable only if no changes are detected after
|
||||||
|
* IMX_KEYPAD_SCANS_FOR_STABILITY scans
|
||||||
|
*/
|
||||||
|
#define IMX_KEYPAD_SCANS_FOR_STABILITY 3
|
||||||
|
int stable_count;
|
||||||
|
|
||||||
|
bool enabled;
|
||||||
|
|
||||||
|
/* Masks for enabled rows/cols */
|
||||||
|
unsigned short rows_en_mask;
|
||||||
|
unsigned short cols_en_mask;
|
||||||
|
|
||||||
|
unsigned short keycodes[MAX_MATRIX_KEY_NUM];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Matrix states:
|
||||||
|
* -stable: achieved after a complete debounce process.
|
||||||
|
* -unstable: used in the debouncing process.
|
||||||
|
*/
|
||||||
|
unsigned short matrix_stable_state[MAX_MATRIX_KEY_COLS];
|
||||||
|
unsigned short matrix_unstable_state[MAX_MATRIX_KEY_COLS];
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Scan the matrix and return the new state in *matrix_volatile_state. */
|
||||||
|
static void imx_keypad_scan_matrix(struct imx_keypad *keypad,
|
||||||
|
unsigned short *matrix_volatile_state)
|
||||||
|
{
|
||||||
|
int col;
|
||||||
|
unsigned short reg_val;
|
||||||
|
|
||||||
|
for (col = 0; col < MAX_MATRIX_KEY_COLS; col++) {
|
||||||
|
if ((keypad->cols_en_mask & (1 << col)) == 0)
|
||||||
|
continue;
|
||||||
|
/*
|
||||||
|
* Discharge keypad capacitance:
|
||||||
|
* 2. write 1s on column data.
|
||||||
|
* 3. configure columns as totem-pole to discharge capacitance.
|
||||||
|
* 4. configure columns as open-drain.
|
||||||
|
*/
|
||||||
|
reg_val = readw(keypad->mmio_base + KPDR);
|
||||||
|
reg_val |= 0xff00;
|
||||||
|
writew(reg_val, keypad->mmio_base + KPDR);
|
||||||
|
|
||||||
|
reg_val = readw(keypad->mmio_base + KPCR);
|
||||||
|
reg_val &= ~((keypad->cols_en_mask & 0xff) << 8);
|
||||||
|
writew(reg_val, keypad->mmio_base + KPCR);
|
||||||
|
|
||||||
|
udelay(2);
|
||||||
|
|
||||||
|
reg_val = readw(keypad->mmio_base + KPCR);
|
||||||
|
reg_val |= (keypad->cols_en_mask & 0xff) << 8;
|
||||||
|
writew(reg_val, keypad->mmio_base + KPCR);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 5. Write a single column to 0, others to 1.
|
||||||
|
* 6. Sample row inputs and save data.
|
||||||
|
* 7. Repeat steps 2 - 6 for remaining columns.
|
||||||
|
*/
|
||||||
|
reg_val = readw(keypad->mmio_base + KPDR);
|
||||||
|
reg_val &= ~(1 << (8 + col));
|
||||||
|
writew(reg_val, keypad->mmio_base + KPDR);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Delay added to avoid propagating the 0 from column to row
|
||||||
|
* when scanning.
|
||||||
|
*/
|
||||||
|
udelay(5);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 1s in matrix_volatile_state[col] means key pressures
|
||||||
|
* throw data from non enabled rows.
|
||||||
|
*/
|
||||||
|
reg_val = readw(keypad->mmio_base + KPDR);
|
||||||
|
matrix_volatile_state[col] = (~reg_val) & keypad->rows_en_mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return in standby mode:
|
||||||
|
* 9. write 0s to columns
|
||||||
|
*/
|
||||||
|
reg_val = readw(keypad->mmio_base + KPDR);
|
||||||
|
reg_val &= 0x00ff;
|
||||||
|
writew(reg_val, keypad->mmio_base + KPDR);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Compare the new matrix state (volatile) with the stable one stored in
|
||||||
|
* keypad->matrix_stable_state and fire events if changes are detected.
|
||||||
|
*/
|
||||||
|
static void imx_keypad_fire_events(struct imx_keypad *keypad,
|
||||||
|
unsigned short *matrix_volatile_state)
|
||||||
|
{
|
||||||
|
struct input_dev *input_dev = keypad->input_dev;
|
||||||
|
int row, col;
|
||||||
|
|
||||||
|
for (col = 0; col < MAX_MATRIX_KEY_COLS; col++) {
|
||||||
|
unsigned short bits_changed;
|
||||||
|
int code;
|
||||||
|
|
||||||
|
if ((keypad->cols_en_mask & (1 << col)) == 0)
|
||||||
|
continue; /* Column is not enabled */
|
||||||
|
|
||||||
|
bits_changed = keypad->matrix_stable_state[col] ^
|
||||||
|
matrix_volatile_state[col];
|
||||||
|
|
||||||
|
if (bits_changed == 0)
|
||||||
|
continue; /* Column does not contain changes */
|
||||||
|
|
||||||
|
for (row = 0; row < MAX_MATRIX_KEY_ROWS; row++) {
|
||||||
|
if ((keypad->rows_en_mask & (1 << row)) == 0)
|
||||||
|
continue; /* Row is not enabled */
|
||||||
|
if ((bits_changed & (1 << row)) == 0)
|
||||||
|
continue; /* Row does not contain changes */
|
||||||
|
|
||||||
|
code = MATRIX_SCAN_CODE(row, col, MATRIX_ROW_SHIFT);
|
||||||
|
input_event(input_dev, EV_MSC, MSC_SCAN, code);
|
||||||
|
input_report_key(input_dev, keypad->keycodes[code],
|
||||||
|
matrix_volatile_state[col] & (1 << row));
|
||||||
|
dev_dbg(&input_dev->dev, "Event code: %d, val: %d",
|
||||||
|
keypad->keycodes[code],
|
||||||
|
matrix_volatile_state[col] & (1 << row));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
input_sync(input_dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* imx_keypad_check_for_events is the timer handler.
|
||||||
|
*/
|
||||||
|
static void imx_keypad_check_for_events(unsigned long data)
|
||||||
|
{
|
||||||
|
struct imx_keypad *keypad = (struct imx_keypad *) data;
|
||||||
|
unsigned short matrix_volatile_state[MAX_MATRIX_KEY_COLS];
|
||||||
|
unsigned short reg_val;
|
||||||
|
bool state_changed, is_zero_matrix;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
memset(matrix_volatile_state, 0, sizeof(matrix_volatile_state));
|
||||||
|
|
||||||
|
imx_keypad_scan_matrix(keypad, matrix_volatile_state);
|
||||||
|
|
||||||
|
state_changed = false;
|
||||||
|
for (i = 0; i < MAX_MATRIX_KEY_COLS; i++) {
|
||||||
|
if ((keypad->cols_en_mask & (1 << i)) == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (keypad->matrix_unstable_state[i] ^ matrix_volatile_state[i]) {
|
||||||
|
state_changed = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the matrix state is changed from the previous scan
|
||||||
|
* (Re)Begin the debouncing process, saving the new state in
|
||||||
|
* keypad->matrix_unstable_state.
|
||||||
|
* else
|
||||||
|
* Increase the count of number of scans with a stable state.
|
||||||
|
*/
|
||||||
|
if (state_changed) {
|
||||||
|
memcpy(keypad->matrix_unstable_state, matrix_volatile_state,
|
||||||
|
sizeof(matrix_volatile_state));
|
||||||
|
keypad->stable_count = 0;
|
||||||
|
} else
|
||||||
|
keypad->stable_count++;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the matrix is not as stable as we want reschedule scan
|
||||||
|
* in the near future.
|
||||||
|
*/
|
||||||
|
if (keypad->stable_count < IMX_KEYPAD_SCANS_FOR_STABILITY) {
|
||||||
|
mod_timer(&keypad->check_matrix_timer,
|
||||||
|
jiffies + msecs_to_jiffies(10));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the matrix state is stable, fire the events and save the new
|
||||||
|
* stable state. Note, if the matrix is kept stable for longer
|
||||||
|
* (keypad->stable_count > IMX_KEYPAD_SCANS_FOR_STABILITY) all
|
||||||
|
* events have already been generated.
|
||||||
|
*/
|
||||||
|
if (keypad->stable_count == IMX_KEYPAD_SCANS_FOR_STABILITY) {
|
||||||
|
imx_keypad_fire_events(keypad, matrix_volatile_state);
|
||||||
|
|
||||||
|
memcpy(keypad->matrix_stable_state, matrix_volatile_state,
|
||||||
|
sizeof(matrix_volatile_state));
|
||||||
|
}
|
||||||
|
|
||||||
|
is_zero_matrix = true;
|
||||||
|
for (i = 0; i < MAX_MATRIX_KEY_COLS; i++) {
|
||||||
|
if (matrix_volatile_state[i] != 0) {
|
||||||
|
is_zero_matrix = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (is_zero_matrix) {
|
||||||
|
/*
|
||||||
|
* All keys have been released. Enable only the KDI
|
||||||
|
* interrupt for future key presses (clear the KDI
|
||||||
|
* status bit and its sync chain before that).
|
||||||
|
*/
|
||||||
|
reg_val = readw(keypad->mmio_base + KPSR);
|
||||||
|
reg_val |= KBD_STAT_KPKD | KBD_STAT_KDSC;
|
||||||
|
writew(reg_val, keypad->mmio_base + KPSR);
|
||||||
|
|
||||||
|
reg_val = readw(keypad->mmio_base + KPSR);
|
||||||
|
reg_val |= KBD_STAT_KDIE;
|
||||||
|
reg_val &= ~KBD_STAT_KRIE;
|
||||||
|
writew(reg_val, keypad->mmio_base + KPSR);
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* Some keys are still pressed. Schedule a rescan in
|
||||||
|
* attempt to detect multiple key presses and enable
|
||||||
|
* the KRI interrupt to react quickly to key release
|
||||||
|
* event.
|
||||||
|
*/
|
||||||
|
mod_timer(&keypad->check_matrix_timer,
|
||||||
|
jiffies + msecs_to_jiffies(60));
|
||||||
|
|
||||||
|
reg_val = readw(keypad->mmio_base + KPSR);
|
||||||
|
reg_val |= KBD_STAT_KPKR | KBD_STAT_KRSS;
|
||||||
|
writew(reg_val, keypad->mmio_base + KPSR);
|
||||||
|
|
||||||
|
reg_val = readw(keypad->mmio_base + KPSR);
|
||||||
|
reg_val |= KBD_STAT_KRIE;
|
||||||
|
reg_val &= ~KBD_STAT_KDIE;
|
||||||
|
writew(reg_val, keypad->mmio_base + KPSR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static irqreturn_t imx_keypad_irq_handler(int irq, void *dev_id)
|
||||||
|
{
|
||||||
|
struct imx_keypad *keypad = dev_id;
|
||||||
|
unsigned short reg_val;
|
||||||
|
|
||||||
|
reg_val = readw(keypad->mmio_base + KPSR);
|
||||||
|
|
||||||
|
/* Disable both interrupt types */
|
||||||
|
reg_val &= ~(KBD_STAT_KRIE | KBD_STAT_KDIE);
|
||||||
|
/* Clear interrupts status bits */
|
||||||
|
reg_val |= KBD_STAT_KPKR | KBD_STAT_KPKD;
|
||||||
|
writew(reg_val, keypad->mmio_base + KPSR);
|
||||||
|
|
||||||
|
if (keypad->enabled) {
|
||||||
|
/* The matrix is supposed to be changed */
|
||||||
|
keypad->stable_count = 0;
|
||||||
|
|
||||||
|
/* Schedule the scanning procedure near in the future */
|
||||||
|
mod_timer(&keypad->check_matrix_timer,
|
||||||
|
jiffies + msecs_to_jiffies(2));
|
||||||
|
}
|
||||||
|
|
||||||
|
return IRQ_HANDLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void imx_keypad_config(struct imx_keypad *keypad)
|
||||||
|
{
|
||||||
|
unsigned short reg_val;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Include enabled rows in interrupt generation (KPCR[7:0])
|
||||||
|
* Configure keypad columns as open-drain (KPCR[15:8])
|
||||||
|
*/
|
||||||
|
reg_val = readw(keypad->mmio_base + KPCR);
|
||||||
|
reg_val |= keypad->rows_en_mask & 0xff; /* rows */
|
||||||
|
reg_val |= (keypad->cols_en_mask & 0xff) << 8; /* cols */
|
||||||
|
writew(reg_val, keypad->mmio_base + KPCR);
|
||||||
|
|
||||||
|
/* Write 0's to KPDR[15:8] (Colums) */
|
||||||
|
reg_val = readw(keypad->mmio_base + KPDR);
|
||||||
|
reg_val &= 0x00ff;
|
||||||
|
writew(reg_val, keypad->mmio_base + KPDR);
|
||||||
|
|
||||||
|
/* Configure columns as output, rows as input (KDDR[15:0]) */
|
||||||
|
writew(0xff00, keypad->mmio_base + KDDR);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Clear Key Depress and Key Release status bit.
|
||||||
|
* Clear both synchronizer chain.
|
||||||
|
*/
|
||||||
|
reg_val = readw(keypad->mmio_base + KPSR);
|
||||||
|
reg_val |= KBD_STAT_KPKR | KBD_STAT_KPKD |
|
||||||
|
KBD_STAT_KDSC | KBD_STAT_KRSS;
|
||||||
|
writew(reg_val, keypad->mmio_base + KPSR);
|
||||||
|
|
||||||
|
/* Enable KDI and disable KRI (avoid false release events). */
|
||||||
|
reg_val |= KBD_STAT_KDIE;
|
||||||
|
reg_val &= ~KBD_STAT_KRIE;
|
||||||
|
writew(reg_val, keypad->mmio_base + KPSR);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void imx_keypad_inhibit(struct imx_keypad *keypad)
|
||||||
|
{
|
||||||
|
unsigned short reg_val;
|
||||||
|
|
||||||
|
/* Inhibit KDI and KRI interrupts. */
|
||||||
|
reg_val = readw(keypad->mmio_base + KPSR);
|
||||||
|
reg_val &= ~(KBD_STAT_KRIE | KBD_STAT_KDIE);
|
||||||
|
writew(reg_val, keypad->mmio_base + KPSR);
|
||||||
|
|
||||||
|
/* Colums as open drain and disable all rows */
|
||||||
|
writew(0xff00, keypad->mmio_base + KPCR);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void imx_keypad_close(struct input_dev *dev)
|
||||||
|
{
|
||||||
|
struct imx_keypad *keypad = input_get_drvdata(dev);
|
||||||
|
|
||||||
|
dev_dbg(&dev->dev, ">%s\n", __func__);
|
||||||
|
|
||||||
|
/* Mark keypad as being inactive */
|
||||||
|
keypad->enabled = false;
|
||||||
|
synchronize_irq(keypad->irq);
|
||||||
|
del_timer_sync(&keypad->check_matrix_timer);
|
||||||
|
|
||||||
|
imx_keypad_inhibit(keypad);
|
||||||
|
|
||||||
|
/* Disable clock unit */
|
||||||
|
clk_disable(keypad->clk);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int imx_keypad_open(struct input_dev *dev)
|
||||||
|
{
|
||||||
|
struct imx_keypad *keypad = input_get_drvdata(dev);
|
||||||
|
|
||||||
|
dev_dbg(&dev->dev, ">%s\n", __func__);
|
||||||
|
|
||||||
|
/* We became active from now */
|
||||||
|
keypad->enabled = true;
|
||||||
|
|
||||||
|
/* Enable the kpp clock */
|
||||||
|
clk_enable(keypad->clk);
|
||||||
|
imx_keypad_config(keypad);
|
||||||
|
|
||||||
|
/* Sanity control, not all the rows must be actived now. */
|
||||||
|
if ((readw(keypad->mmio_base + KPDR) & keypad->rows_en_mask) == 0) {
|
||||||
|
dev_err(&dev->dev,
|
||||||
|
"too many keys pressed, control pins initialisation\n");
|
||||||
|
goto open_err;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
open_err:
|
||||||
|
imx_keypad_close(dev);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __devinit imx_keypad_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
const struct matrix_keymap_data *keymap_data = pdev->dev.platform_data;
|
||||||
|
struct imx_keypad *keypad;
|
||||||
|
struct input_dev *input_dev;
|
||||||
|
struct resource *res;
|
||||||
|
int irq, error, i;
|
||||||
|
|
||||||
|
if (keymap_data == NULL) {
|
||||||
|
dev_err(&pdev->dev, "no keymap defined\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
irq = platform_get_irq(pdev, 0);
|
||||||
|
if (irq < 0) {
|
||||||
|
dev_err(&pdev->dev, "no irq defined in platform data\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||||
|
if (res == NULL) {
|
||||||
|
dev_err(&pdev->dev, "no I/O memory defined in platform data\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
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");
|
||||||
|
return -EBUSY;
|
||||||
|
}
|
||||||
|
|
||||||
|
input_dev = input_allocate_device();
|
||||||
|
if (!input_dev) {
|
||||||
|
dev_err(&pdev->dev, "failed to allocate the input device\n");
|
||||||
|
error = -ENOMEM;
|
||||||
|
goto failed_rel_mem;
|
||||||
|
}
|
||||||
|
|
||||||
|
keypad = kzalloc(sizeof(struct imx_keypad), GFP_KERNEL);
|
||||||
|
if (!keypad) {
|
||||||
|
dev_err(&pdev->dev, "not enough memory for driver data\n");
|
||||||
|
error = -ENOMEM;
|
||||||
|
goto failed_free_input;
|
||||||
|
}
|
||||||
|
|
||||||
|
keypad->input_dev = input_dev;
|
||||||
|
keypad->irq = irq;
|
||||||
|
keypad->stable_count = 0;
|
||||||
|
|
||||||
|
setup_timer(&keypad->check_matrix_timer,
|
||||||
|
imx_keypad_check_for_events, (unsigned long) keypad);
|
||||||
|
|
||||||
|
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 = -ENOMEM;
|
||||||
|
goto failed_free_priv;
|
||||||
|
}
|
||||||
|
|
||||||
|
keypad->clk = clk_get(&pdev->dev, "kpp");
|
||||||
|
if (IS_ERR(keypad->clk)) {
|
||||||
|
dev_err(&pdev->dev, "failed to get keypad clock\n");
|
||||||
|
error = PTR_ERR(keypad->clk);
|
||||||
|
goto failed_unmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Search for rows and cols enabled */
|
||||||
|
for (i = 0; i < keymap_data->keymap_size; i++) {
|
||||||
|
keypad->rows_en_mask |= 1 << KEY_ROW(keymap_data->keymap[i]);
|
||||||
|
keypad->cols_en_mask |= 1 << KEY_COL(keymap_data->keymap[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (keypad->rows_en_mask > ((1 << MAX_MATRIX_KEY_ROWS) - 1) ||
|
||||||
|
keypad->cols_en_mask > ((1 << MAX_MATRIX_KEY_COLS) - 1)) {
|
||||||
|
dev_err(&pdev->dev,
|
||||||
|
"invalid key data (too many rows or colums)\n");
|
||||||
|
error = -EINVAL;
|
||||||
|
goto failed_clock_put;
|
||||||
|
}
|
||||||
|
dev_dbg(&pdev->dev, "enabled rows mask: %x\n", keypad->rows_en_mask);
|
||||||
|
dev_dbg(&pdev->dev, "enabled cols mask: %x\n", keypad->cols_en_mask);
|
||||||
|
|
||||||
|
/* Init the Input device */
|
||||||
|
input_dev->name = pdev->name;
|
||||||
|
input_dev->id.bustype = BUS_HOST;
|
||||||
|
input_dev->dev.parent = &pdev->dev;
|
||||||
|
input_dev->open = imx_keypad_open;
|
||||||
|
input_dev->close = imx_keypad_close;
|
||||||
|
input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
|
||||||
|
input_dev->keycode = keypad->keycodes;
|
||||||
|
input_dev->keycodesize = sizeof(keypad->keycodes[0]);
|
||||||
|
input_dev->keycodemax = ARRAY_SIZE(keypad->keycodes);
|
||||||
|
|
||||||
|
matrix_keypad_build_keymap(keymap_data, MATRIX_ROW_SHIFT,
|
||||||
|
keypad->keycodes, input_dev->keybit);
|
||||||
|
|
||||||
|
input_set_capability(input_dev, EV_MSC, MSC_SCAN);
|
||||||
|
input_set_drvdata(input_dev, keypad);
|
||||||
|
|
||||||
|
/* Ensure that the keypad will stay dormant until opened */
|
||||||
|
imx_keypad_inhibit(keypad);
|
||||||
|
|
||||||
|
error = request_irq(irq, imx_keypad_irq_handler, IRQF_DISABLED,
|
||||||
|
pdev->name, keypad);
|
||||||
|
if (error) {
|
||||||
|
dev_err(&pdev->dev, "failed to request IRQ\n");
|
||||||
|
goto failed_clock_put;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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);
|
||||||
|
device_init_wakeup(&pdev->dev, 1);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
failed_free_irq:
|
||||||
|
free_irq(irq, pdev);
|
||||||
|
failed_clock_put:
|
||||||
|
clk_put(keypad->clk);
|
||||||
|
failed_unmap:
|
||||||
|
iounmap(keypad->mmio_base);
|
||||||
|
failed_free_priv:
|
||||||
|
kfree(keypad);
|
||||||
|
failed_free_input:
|
||||||
|
input_free_device(input_dev);
|
||||||
|
failed_rel_mem:
|
||||||
|
release_mem_region(res->start, resource_size(res));
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __devexit imx_keypad_remove(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct imx_keypad *keypad = platform_get_drvdata(pdev);
|
||||||
|
struct resource *res;
|
||||||
|
|
||||||
|
dev_dbg(&pdev->dev, ">%s\n", __func__);
|
||||||
|
|
||||||
|
platform_set_drvdata(pdev, NULL);
|
||||||
|
|
||||||
|
input_unregister_device(keypad->input_dev);
|
||||||
|
|
||||||
|
free_irq(keypad->irq, keypad);
|
||||||
|
clk_put(keypad->clk);
|
||||||
|
|
||||||
|
iounmap(keypad->mmio_base);
|
||||||
|
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||||
|
release_mem_region(res->start, resource_size(res));
|
||||||
|
|
||||||
|
kfree(keypad);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct platform_driver imx_keypad_driver = {
|
||||||
|
.driver = {
|
||||||
|
.name = "imx-keypad",
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
},
|
||||||
|
.probe = imx_keypad_probe,
|
||||||
|
.remove = __devexit_p(imx_keypad_remove),
|
||||||
|
};
|
||||||
|
|
||||||
|
static int __init imx_keypad_init(void)
|
||||||
|
{
|
||||||
|
return platform_driver_register(&imx_keypad_driver);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __exit imx_keypad_exit(void)
|
||||||
|
{
|
||||||
|
platform_driver_unregister(&imx_keypad_driver);
|
||||||
|
}
|
||||||
|
|
||||||
|
module_init(imx_keypad_init);
|
||||||
|
module_exit(imx_keypad_exit);
|
||||||
|
|
||||||
|
MODULE_AUTHOR("Alberto Panizzo <maramaopercheseimorto@gmail.com>");
|
||||||
|
MODULE_DESCRIPTION("IMX Keypad Port Driver");
|
||||||
|
MODULE_LICENSE("GPL v2");
|
||||||
|
MODULE_ALIAS("platform:imx-keypad");
|
||||||
|
|
@ -362,7 +362,7 @@ static int __devexit qt2160_remove(struct i2c_client *client)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct i2c_device_id qt2160_idtable[] = {
|
static const struct i2c_device_id qt2160_idtable[] = {
|
||||||
{ "qt2160", 0, },
|
{ "qt2160", 0, },
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -19,101 +19,141 @@
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/input.h>
|
#include <linux/input.h>
|
||||||
#include <linux/input/sh_keysc.h>
|
#include <linux/input/sh_keysc.h>
|
||||||
|
#include <linux/bitmap.h>
|
||||||
#include <linux/clk.h>
|
#include <linux/clk.h>
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
|
|
||||||
#define KYCR1_OFFS 0x00
|
|
||||||
#define KYCR2_OFFS 0x04
|
|
||||||
#define KYINDR_OFFS 0x08
|
|
||||||
#define KYOUTDR_OFFS 0x0c
|
|
||||||
|
|
||||||
#define KYCR2_IRQ_LEVEL 0x10
|
|
||||||
#define KYCR2_IRQ_DISABLED 0x00
|
|
||||||
|
|
||||||
static const struct {
|
static const struct {
|
||||||
unsigned char kymd, keyout, keyin;
|
unsigned char kymd, keyout, keyin;
|
||||||
} sh_keysc_mode[] = {
|
} sh_keysc_mode[] = {
|
||||||
[SH_KEYSC_MODE_1] = { 0, 6, 5 },
|
[SH_KEYSC_MODE_1] = { 0, 6, 5 },
|
||||||
[SH_KEYSC_MODE_2] = { 1, 5, 6 },
|
[SH_KEYSC_MODE_2] = { 1, 5, 6 },
|
||||||
[SH_KEYSC_MODE_3] = { 2, 4, 7 },
|
[SH_KEYSC_MODE_3] = { 2, 4, 7 },
|
||||||
|
[SH_KEYSC_MODE_4] = { 3, 6, 6 },
|
||||||
|
[SH_KEYSC_MODE_5] = { 4, 6, 7 },
|
||||||
|
[SH_KEYSC_MODE_6] = { 5, 7, 7 },
|
||||||
};
|
};
|
||||||
|
|
||||||
struct sh_keysc_priv {
|
struct sh_keysc_priv {
|
||||||
void __iomem *iomem_base;
|
void __iomem *iomem_base;
|
||||||
struct clk *clk;
|
struct clk *clk;
|
||||||
unsigned long last_keys;
|
DECLARE_BITMAP(last_keys, SH_KEYSC_MAXKEYS);
|
||||||
struct input_dev *input;
|
struct input_dev *input;
|
||||||
struct sh_keysc_info pdata;
|
struct sh_keysc_info pdata;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define KYCR1 0
|
||||||
|
#define KYCR2 1
|
||||||
|
#define KYINDR 2
|
||||||
|
#define KYOUTDR 3
|
||||||
|
|
||||||
|
#define KYCR2_IRQ_LEVEL 0x10
|
||||||
|
#define KYCR2_IRQ_DISABLED 0x00
|
||||||
|
|
||||||
|
static unsigned long sh_keysc_read(struct sh_keysc_priv *p, int reg_nr)
|
||||||
|
{
|
||||||
|
return ioread16(p->iomem_base + (reg_nr << 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sh_keysc_write(struct sh_keysc_priv *p, int reg_nr,
|
||||||
|
unsigned long value)
|
||||||
|
{
|
||||||
|
iowrite16(value, p->iomem_base + (reg_nr << 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sh_keysc_level_mode(struct sh_keysc_priv *p,
|
||||||
|
unsigned long keys_set)
|
||||||
|
{
|
||||||
|
struct sh_keysc_info *pdata = &p->pdata;
|
||||||
|
|
||||||
|
sh_keysc_write(p, KYOUTDR, 0);
|
||||||
|
sh_keysc_write(p, KYCR2, KYCR2_IRQ_LEVEL | (keys_set << 8));
|
||||||
|
|
||||||
|
if (pdata->kycr2_delay)
|
||||||
|
udelay(pdata->kycr2_delay);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sh_keysc_map_dbg(struct device *dev, unsigned long *map,
|
||||||
|
const char *str)
|
||||||
|
{
|
||||||
|
int k;
|
||||||
|
|
||||||
|
for (k = 0; k < BITS_TO_LONGS(SH_KEYSC_MAXKEYS); k++)
|
||||||
|
dev_dbg(dev, "%s[%d] 0x%lx\n", str, k, map[k]);
|
||||||
|
}
|
||||||
|
|
||||||
static irqreturn_t sh_keysc_isr(int irq, void *dev_id)
|
static irqreturn_t sh_keysc_isr(int irq, void *dev_id)
|
||||||
{
|
{
|
||||||
struct platform_device *pdev = dev_id;
|
struct platform_device *pdev = dev_id;
|
||||||
struct sh_keysc_priv *priv = platform_get_drvdata(pdev);
|
struct sh_keysc_priv *priv = platform_get_drvdata(pdev);
|
||||||
struct sh_keysc_info *pdata = &priv->pdata;
|
struct sh_keysc_info *pdata = &priv->pdata;
|
||||||
unsigned long keys, keys1, keys0, mask;
|
int keyout_nr = sh_keysc_mode[pdata->mode].keyout;
|
||||||
|
int keyin_nr = sh_keysc_mode[pdata->mode].keyin;
|
||||||
|
DECLARE_BITMAP(keys, SH_KEYSC_MAXKEYS);
|
||||||
|
DECLARE_BITMAP(keys0, SH_KEYSC_MAXKEYS);
|
||||||
|
DECLARE_BITMAP(keys1, SH_KEYSC_MAXKEYS);
|
||||||
unsigned char keyin_set, tmp;
|
unsigned char keyin_set, tmp;
|
||||||
int i, k;
|
int i, k, n;
|
||||||
|
|
||||||
dev_dbg(&pdev->dev, "isr!\n");
|
dev_dbg(&pdev->dev, "isr!\n");
|
||||||
|
|
||||||
keys1 = ~0;
|
bitmap_fill(keys1, SH_KEYSC_MAXKEYS);
|
||||||
keys0 = 0;
|
bitmap_zero(keys0, SH_KEYSC_MAXKEYS);
|
||||||
|
|
||||||
do {
|
do {
|
||||||
keys = 0;
|
bitmap_zero(keys, SH_KEYSC_MAXKEYS);
|
||||||
keyin_set = 0;
|
keyin_set = 0;
|
||||||
|
|
||||||
iowrite16(KYCR2_IRQ_DISABLED, priv->iomem_base + KYCR2_OFFS);
|
sh_keysc_write(priv, KYCR2, KYCR2_IRQ_DISABLED);
|
||||||
|
|
||||||
for (i = 0; i < sh_keysc_mode[pdata->mode].keyout; i++) {
|
for (i = 0; i < keyout_nr; i++) {
|
||||||
iowrite16(0xfff ^ (3 << (i * 2)),
|
n = keyin_nr * i;
|
||||||
priv->iomem_base + KYOUTDR_OFFS);
|
|
||||||
|
/* drive one KEYOUT pin low, read KEYIN pins */
|
||||||
|
sh_keysc_write(priv, KYOUTDR, 0xffff ^ (3 << (i * 2)));
|
||||||
udelay(pdata->delay);
|
udelay(pdata->delay);
|
||||||
tmp = ioread16(priv->iomem_base + KYINDR_OFFS);
|
tmp = sh_keysc_read(priv, KYINDR);
|
||||||
keys |= tmp << (sh_keysc_mode[pdata->mode].keyin * i);
|
|
||||||
tmp ^= (1 << sh_keysc_mode[pdata->mode].keyin) - 1;
|
/* set bit if key press has been detected */
|
||||||
keyin_set |= tmp;
|
for (k = 0; k < keyin_nr; k++) {
|
||||||
|
if (tmp & (1 << k))
|
||||||
|
__set_bit(n + k, keys);
|
||||||
}
|
}
|
||||||
|
|
||||||
iowrite16(0, priv->iomem_base + KYOUTDR_OFFS);
|
/* keep track of which KEYIN bits that have been set */
|
||||||
iowrite16(KYCR2_IRQ_LEVEL | (keyin_set << 8),
|
keyin_set |= tmp ^ ((1 << keyin_nr) - 1);
|
||||||
priv->iomem_base + KYCR2_OFFS);
|
}
|
||||||
|
|
||||||
if (pdata->kycr2_delay)
|
sh_keysc_level_mode(priv, keyin_set);
|
||||||
udelay(pdata->kycr2_delay);
|
|
||||||
|
|
||||||
keys ^= ~0;
|
bitmap_complement(keys, keys, SH_KEYSC_MAXKEYS);
|
||||||
keys &= (1 << (sh_keysc_mode[pdata->mode].keyin *
|
bitmap_and(keys1, keys1, keys, SH_KEYSC_MAXKEYS);
|
||||||
sh_keysc_mode[pdata->mode].keyout)) - 1;
|
bitmap_or(keys0, keys0, keys, SH_KEYSC_MAXKEYS);
|
||||||
keys1 &= keys;
|
|
||||||
keys0 |= keys;
|
|
||||||
|
|
||||||
dev_dbg(&pdev->dev, "keys 0x%08lx\n", keys);
|
sh_keysc_map_dbg(&pdev->dev, keys, "keys");
|
||||||
|
|
||||||
} while (ioread16(priv->iomem_base + KYCR2_OFFS) & 0x01);
|
} while (sh_keysc_read(priv, KYCR2) & 0x01);
|
||||||
|
|
||||||
dev_dbg(&pdev->dev, "last_keys 0x%08lx keys0 0x%08lx keys1 0x%08lx\n",
|
sh_keysc_map_dbg(&pdev->dev, priv->last_keys, "last_keys");
|
||||||
priv->last_keys, keys0, keys1);
|
sh_keysc_map_dbg(&pdev->dev, keys0, "keys0");
|
||||||
|
sh_keysc_map_dbg(&pdev->dev, keys1, "keys1");
|
||||||
|
|
||||||
for (i = 0; i < SH_KEYSC_MAXKEYS; i++) {
|
for (i = 0; i < SH_KEYSC_MAXKEYS; i++) {
|
||||||
k = pdata->keycodes[i];
|
k = pdata->keycodes[i];
|
||||||
if (!k)
|
if (!k)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
mask = 1 << i;
|
if (test_bit(i, keys0) == test_bit(i, priv->last_keys))
|
||||||
|
|
||||||
if (!((priv->last_keys ^ keys0) & mask))
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if ((keys1 | keys0) & mask) {
|
if (test_bit(i, keys1) || test_bit(i, keys0)) {
|
||||||
input_event(priv->input, EV_KEY, k, 1);
|
input_event(priv->input, EV_KEY, k, 1);
|
||||||
priv->last_keys |= mask;
|
__set_bit(i, priv->last_keys);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(keys1 & mask)) {
|
if (!test_bit(i, keys1)) {
|
||||||
input_event(priv->input, EV_KEY, k, 0);
|
input_event(priv->input, EV_KEY, k, 0);
|
||||||
priv->last_keys &= ~mask;
|
__clear_bit(i, priv->last_keys);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -122,8 +162,6 @@ static irqreturn_t sh_keysc_isr(int irq, void *dev_id)
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define res_size(res) ((res)->end - (res)->start + 1)
|
|
||||||
|
|
||||||
static int __devinit sh_keysc_probe(struct platform_device *pdev)
|
static int __devinit sh_keysc_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct sh_keysc_priv *priv;
|
struct sh_keysc_priv *priv;
|
||||||
|
|
@ -164,7 +202,7 @@ static int __devinit sh_keysc_probe(struct platform_device *pdev)
|
||||||
memcpy(&priv->pdata, pdev->dev.platform_data, sizeof(priv->pdata));
|
memcpy(&priv->pdata, pdev->dev.platform_data, sizeof(priv->pdata));
|
||||||
pdata = &priv->pdata;
|
pdata = &priv->pdata;
|
||||||
|
|
||||||
priv->iomem_base = ioremap_nocache(res->start, res_size(res));
|
priv->iomem_base = ioremap_nocache(res->start, resource_size(res));
|
||||||
if (priv->iomem_base == NULL) {
|
if (priv->iomem_base == NULL) {
|
||||||
dev_err(&pdev->dev, "failed to remap I/O memory\n");
|
dev_err(&pdev->dev, "failed to remap I/O memory\n");
|
||||||
error = -ENXIO;
|
error = -ENXIO;
|
||||||
|
|
@ -220,10 +258,9 @@ static int __devinit sh_keysc_probe(struct platform_device *pdev)
|
||||||
|
|
||||||
clk_enable(priv->clk);
|
clk_enable(priv->clk);
|
||||||
|
|
||||||
iowrite16((sh_keysc_mode[pdata->mode].kymd << 8) |
|
sh_keysc_write(priv, KYCR1, (sh_keysc_mode[pdata->mode].kymd << 8) |
|
||||||
pdata->scan_timing, priv->iomem_base + KYCR1_OFFS);
|
pdata->scan_timing);
|
||||||
iowrite16(0, priv->iomem_base + KYOUTDR_OFFS);
|
sh_keysc_level_mode(priv, 0);
|
||||||
iowrite16(KYCR2_IRQ_LEVEL, priv->iomem_base + KYCR2_OFFS);
|
|
||||||
|
|
||||||
device_init_wakeup(&pdev->dev, 1);
|
device_init_wakeup(&pdev->dev, 1);
|
||||||
|
|
||||||
|
|
@ -248,7 +285,7 @@ static int __devexit sh_keysc_remove(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct sh_keysc_priv *priv = platform_get_drvdata(pdev);
|
struct sh_keysc_priv *priv = platform_get_drvdata(pdev);
|
||||||
|
|
||||||
iowrite16(KYCR2_IRQ_DISABLED, priv->iomem_base + KYCR2_OFFS);
|
sh_keysc_write(priv, KYCR2, KYCR2_IRQ_DISABLED);
|
||||||
|
|
||||||
input_unregister_device(priv->input);
|
input_unregister_device(priv->input);
|
||||||
free_irq(platform_get_irq(pdev, 0), pdev);
|
free_irq(platform_get_irq(pdev, 0), pdev);
|
||||||
|
|
@ -270,7 +307,7 @@ static int sh_keysc_suspend(struct device *dev)
|
||||||
int irq = platform_get_irq(pdev, 0);
|
int irq = platform_get_irq(pdev, 0);
|
||||||
unsigned short value;
|
unsigned short value;
|
||||||
|
|
||||||
value = ioread16(priv->iomem_base + KYCR1_OFFS);
|
value = sh_keysc_read(priv, KYCR1);
|
||||||
|
|
||||||
if (device_may_wakeup(dev)) {
|
if (device_may_wakeup(dev)) {
|
||||||
value |= 0x80;
|
value |= 0x80;
|
||||||
|
|
@ -279,7 +316,7 @@ static int sh_keysc_suspend(struct device *dev)
|
||||||
value &= ~0x80;
|
value &= ~0x80;
|
||||||
}
|
}
|
||||||
|
|
||||||
iowrite16(value, priv->iomem_base + KYCR1_OFFS);
|
sh_keysc_write(priv, KYCR1, value);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -149,7 +149,7 @@ static void apanel_shutdown(struct i2c_client *client)
|
||||||
apanel_remove(client);
|
apanel_remove(client);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct i2c_device_id apanel_id[] = {
|
static const struct i2c_device_id apanel_id[] = {
|
||||||
{ "fujitsu_apanel", 0 },
|
{ "fujitsu_apanel", 0 },
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -152,6 +152,13 @@ static int __devinit rotary_encoder_probe(struct platform_device *pdev)
|
||||||
goto exit_unregister_input;
|
goto exit_unregister_input;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = gpio_direction_input(pdata->gpio_a);
|
||||||
|
if (err) {
|
||||||
|
dev_err(&pdev->dev, "unable to set GPIO %d for input\n",
|
||||||
|
pdata->gpio_a);
|
||||||
|
goto exit_unregister_input;
|
||||||
|
}
|
||||||
|
|
||||||
err = gpio_request(pdata->gpio_b, DRV_NAME);
|
err = gpio_request(pdata->gpio_b, DRV_NAME);
|
||||||
if (err) {
|
if (err) {
|
||||||
dev_err(&pdev->dev, "unable to request GPIO %d\n",
|
dev_err(&pdev->dev, "unable to request GPIO %d\n",
|
||||||
|
|
@ -159,6 +166,13 @@ static int __devinit rotary_encoder_probe(struct platform_device *pdev)
|
||||||
goto exit_free_gpio_a;
|
goto exit_free_gpio_a;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = gpio_direction_input(pdata->gpio_b);
|
||||||
|
if (err) {
|
||||||
|
dev_err(&pdev->dev, "unable to set GPIO %d for input\n",
|
||||||
|
pdata->gpio_b);
|
||||||
|
goto exit_free_gpio_a;
|
||||||
|
}
|
||||||
|
|
||||||
/* request the IRQs */
|
/* request the IRQs */
|
||||||
err = request_irq(encoder->irq_a, &rotary_encoder_irq,
|
err = request_irq(encoder->irq_a, &rotary_encoder_irq,
|
||||||
IORESOURCE_IRQ_HIGHEDGE | IORESOURCE_IRQ_LOWEDGE,
|
IORESOURCE_IRQ_HIGHEDGE | IORESOURCE_IRQ_LOWEDGE,
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,6 @@
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/smp_lock.h>
|
|
||||||
#include <linux/fs.h>
|
#include <linux/fs.h>
|
||||||
#include <linux/miscdevice.h>
|
#include <linux/miscdevice.h>
|
||||||
#include <linux/uinput.h>
|
#include <linux/uinput.h>
|
||||||
|
|
@ -284,7 +283,6 @@ static int uinput_open(struct inode *inode, struct file *file)
|
||||||
if (!newdev)
|
if (!newdev)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
lock_kernel();
|
|
||||||
mutex_init(&newdev->mutex);
|
mutex_init(&newdev->mutex);
|
||||||
spin_lock_init(&newdev->requests_lock);
|
spin_lock_init(&newdev->requests_lock);
|
||||||
init_waitqueue_head(&newdev->requests_waitq);
|
init_waitqueue_head(&newdev->requests_waitq);
|
||||||
|
|
@ -292,7 +290,7 @@ static int uinput_open(struct inode *inode, struct file *file)
|
||||||
newdev->state = UIST_NEW_DEVICE;
|
newdev->state = UIST_NEW_DEVICE;
|
||||||
|
|
||||||
file->private_data = newdev;
|
file->private_data = newdev;
|
||||||
unlock_kernel();
|
nonseekable_open(inode, file);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -538,6 +538,7 @@ wbcir_reset_irdata(struct wbcir_data *data)
|
||||||
data->irdata_count = 0;
|
data->irdata_count = 0;
|
||||||
data->irdata_off = 0;
|
data->irdata_off = 0;
|
||||||
data->irdata_error = 0;
|
data->irdata_error = 0;
|
||||||
|
data->idle_count = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Adds one bit of irdata */
|
/* Adds one bit of irdata */
|
||||||
|
|
@ -1006,7 +1007,6 @@ wbcir_irq_handler(int irqno, void *cookie)
|
||||||
}
|
}
|
||||||
|
|
||||||
wbcir_reset_irdata(data);
|
wbcir_reset_irdata(data);
|
||||||
data->idle_count = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
|
|
@ -1018,7 +1018,7 @@ out:
|
||||||
|
|
||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
*
|
*
|
||||||
* SUSPEND/RESUME FUNCTIONS
|
* SETUP/INIT/SUSPEND/RESUME FUNCTIONS
|
||||||
*
|
*
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
|
|
@ -1197,7 +1197,16 @@ finish:
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Disable interrupts */
|
/* Disable interrupts */
|
||||||
|
wbcir_select_bank(data, WBCIR_BANK_0);
|
||||||
outb(WBCIR_IRQ_NONE, data->sbase + WBCIR_REG_SP3_IER);
|
outb(WBCIR_IRQ_NONE, data->sbase + WBCIR_REG_SP3_IER);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ACPI will set the HW disable bit for SP3 which means that the
|
||||||
|
* output signals are left in an undefined state which may cause
|
||||||
|
* spurious interrupts which we need to ignore until the hardware
|
||||||
|
* is reinitialized.
|
||||||
|
*/
|
||||||
|
disable_irq(data->irq);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
|
@ -1207,37 +1216,15 @@ wbcir_suspend(struct pnp_dev *device, pm_message_t state)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
|
||||||
wbcir_resume(struct pnp_dev *device)
|
|
||||||
{
|
|
||||||
struct wbcir_data *data = pnp_get_drvdata(device);
|
|
||||||
|
|
||||||
/* Clear BUFF_EN, Clear END_EN, Clear MATCH_EN */
|
|
||||||
wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_EV_EN, 0x00, 0x07);
|
|
||||||
|
|
||||||
/* Clear CEIR_EN */
|
|
||||||
wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_CTL, 0x00, 0x01);
|
|
||||||
|
|
||||||
/* Enable interrupts */
|
|
||||||
wbcir_reset_irdata(data);
|
|
||||||
outb(WBCIR_IRQ_RX | WBCIR_IRQ_ERR, data->sbase + WBCIR_REG_SP3_IER);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*****************************************************************************
|
|
||||||
*
|
|
||||||
* SETUP/INIT FUNCTIONS
|
|
||||||
*
|
|
||||||
*****************************************************************************/
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
wbcir_cfg_ceir(struct wbcir_data *data)
|
wbcir_init_hw(struct wbcir_data *data)
|
||||||
{
|
{
|
||||||
u8 tmp;
|
u8 tmp;
|
||||||
|
|
||||||
|
/* Disable interrupts */
|
||||||
|
wbcir_select_bank(data, WBCIR_BANK_0);
|
||||||
|
outb(WBCIR_IRQ_NONE, data->sbase + WBCIR_REG_SP3_IER);
|
||||||
|
|
||||||
/* Set PROT_SEL, RX_INV, Clear CEIR_EN (needed for the led) */
|
/* Set PROT_SEL, RX_INV, Clear CEIR_EN (needed for the led) */
|
||||||
tmp = protocol << 4;
|
tmp = protocol << 4;
|
||||||
if (invert)
|
if (invert)
|
||||||
|
|
@ -1264,6 +1251,93 @@ wbcir_cfg_ceir(struct wbcir_data *data)
|
||||||
* set SP3_IRRX_SW to binary 01, helpfully not documented
|
* set SP3_IRRX_SW to binary 01, helpfully not documented
|
||||||
*/
|
*/
|
||||||
outb(0x10, data->ebase + WBCIR_REG_ECEIR_CTS);
|
outb(0x10, data->ebase + WBCIR_REG_ECEIR_CTS);
|
||||||
|
|
||||||
|
/* Enable extended mode */
|
||||||
|
wbcir_select_bank(data, WBCIR_BANK_2);
|
||||||
|
outb(WBCIR_EXT_ENABLE, data->sbase + WBCIR_REG_SP3_EXCR1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Configure baud generator, IR data will be sampled at
|
||||||
|
* a bitrate of: (24Mhz * prescaler) / (divisor * 16).
|
||||||
|
*
|
||||||
|
* The ECIR registers include a flag to change the
|
||||||
|
* 24Mhz clock freq to 48Mhz.
|
||||||
|
*
|
||||||
|
* It's not documented in the specs, but fifo levels
|
||||||
|
* other than 16 seems to be unsupported.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* prescaler 1.0, tx/rx fifo lvl 16 */
|
||||||
|
outb(0x30, data->sbase + WBCIR_REG_SP3_EXCR2);
|
||||||
|
|
||||||
|
/* Set baud divisor to generate one byte per bit/cell */
|
||||||
|
switch (protocol) {
|
||||||
|
case IR_PROTOCOL_RC5:
|
||||||
|
outb(0xA7, data->sbase + WBCIR_REG_SP3_BGDL);
|
||||||
|
break;
|
||||||
|
case IR_PROTOCOL_RC6:
|
||||||
|
outb(0x53, data->sbase + WBCIR_REG_SP3_BGDL);
|
||||||
|
break;
|
||||||
|
case IR_PROTOCOL_NEC:
|
||||||
|
outb(0x69, data->sbase + WBCIR_REG_SP3_BGDL);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
outb(0x00, data->sbase + WBCIR_REG_SP3_BGDH);
|
||||||
|
|
||||||
|
/* Set CEIR mode */
|
||||||
|
wbcir_select_bank(data, WBCIR_BANK_0);
|
||||||
|
outb(0xC0, data->sbase + WBCIR_REG_SP3_MCR);
|
||||||
|
inb(data->sbase + WBCIR_REG_SP3_LSR); /* Clear LSR */
|
||||||
|
inb(data->sbase + WBCIR_REG_SP3_MSR); /* Clear MSR */
|
||||||
|
|
||||||
|
/* Disable RX demod, run-length encoding/decoding, set freq span */
|
||||||
|
wbcir_select_bank(data, WBCIR_BANK_7);
|
||||||
|
outb(0x10, data->sbase + WBCIR_REG_SP3_RCCFG);
|
||||||
|
|
||||||
|
/* Disable timer */
|
||||||
|
wbcir_select_bank(data, WBCIR_BANK_4);
|
||||||
|
outb(0x00, data->sbase + WBCIR_REG_SP3_IRCR1);
|
||||||
|
|
||||||
|
/* Enable MSR interrupt, Clear AUX_IRX */
|
||||||
|
wbcir_select_bank(data, WBCIR_BANK_5);
|
||||||
|
outb(0x00, data->sbase + WBCIR_REG_SP3_IRCR2);
|
||||||
|
|
||||||
|
/* Disable CRC */
|
||||||
|
wbcir_select_bank(data, WBCIR_BANK_6);
|
||||||
|
outb(0x20, data->sbase + WBCIR_REG_SP3_IRCR3);
|
||||||
|
|
||||||
|
/* Set RX/TX (de)modulation freq, not really used */
|
||||||
|
wbcir_select_bank(data, WBCIR_BANK_7);
|
||||||
|
outb(0xF2, data->sbase + WBCIR_REG_SP3_IRRXDC);
|
||||||
|
outb(0x69, data->sbase + WBCIR_REG_SP3_IRTXMC);
|
||||||
|
|
||||||
|
/* Set invert and pin direction */
|
||||||
|
if (invert)
|
||||||
|
outb(0x10, data->sbase + WBCIR_REG_SP3_IRCFG4);
|
||||||
|
else
|
||||||
|
outb(0x00, data->sbase + WBCIR_REG_SP3_IRCFG4);
|
||||||
|
|
||||||
|
/* Set FIFO thresholds (RX = 8, TX = 3), reset RX/TX */
|
||||||
|
wbcir_select_bank(data, WBCIR_BANK_0);
|
||||||
|
outb(0x97, data->sbase + WBCIR_REG_SP3_FCR);
|
||||||
|
|
||||||
|
/* Clear AUX status bits */
|
||||||
|
outb(0xE0, data->sbase + WBCIR_REG_SP3_ASCR);
|
||||||
|
|
||||||
|
/* Enable interrupts */
|
||||||
|
wbcir_reset_irdata(data);
|
||||||
|
outb(WBCIR_IRQ_RX | WBCIR_IRQ_ERR, data->sbase + WBCIR_REG_SP3_IER);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
wbcir_resume(struct pnp_dev *device)
|
||||||
|
{
|
||||||
|
struct wbcir_data *data = pnp_get_drvdata(device);
|
||||||
|
|
||||||
|
wbcir_init_hw(data);
|
||||||
|
enable_irq(data->irq);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __devinit
|
static int __devinit
|
||||||
|
|
@ -1393,86 +1467,7 @@ wbcir_probe(struct pnp_dev *device, const struct pnp_device_id *dev_id)
|
||||||
|
|
||||||
device_init_wakeup(&device->dev, 1);
|
device_init_wakeup(&device->dev, 1);
|
||||||
|
|
||||||
wbcir_cfg_ceir(data);
|
wbcir_init_hw(data);
|
||||||
|
|
||||||
/* Disable interrupts */
|
|
||||||
wbcir_select_bank(data, WBCIR_BANK_0);
|
|
||||||
outb(WBCIR_IRQ_NONE, data->sbase + WBCIR_REG_SP3_IER);
|
|
||||||
|
|
||||||
/* Enable extended mode */
|
|
||||||
wbcir_select_bank(data, WBCIR_BANK_2);
|
|
||||||
outb(WBCIR_EXT_ENABLE, data->sbase + WBCIR_REG_SP3_EXCR1);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Configure baud generator, IR data will be sampled at
|
|
||||||
* a bitrate of: (24Mhz * prescaler) / (divisor * 16).
|
|
||||||
*
|
|
||||||
* The ECIR registers include a flag to change the
|
|
||||||
* 24Mhz clock freq to 48Mhz.
|
|
||||||
*
|
|
||||||
* It's not documented in the specs, but fifo levels
|
|
||||||
* other than 16 seems to be unsupported.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* prescaler 1.0, tx/rx fifo lvl 16 */
|
|
||||||
outb(0x30, data->sbase + WBCIR_REG_SP3_EXCR2);
|
|
||||||
|
|
||||||
/* Set baud divisor to generate one byte per bit/cell */
|
|
||||||
switch (protocol) {
|
|
||||||
case IR_PROTOCOL_RC5:
|
|
||||||
outb(0xA7, data->sbase + WBCIR_REG_SP3_BGDL);
|
|
||||||
break;
|
|
||||||
case IR_PROTOCOL_RC6:
|
|
||||||
outb(0x53, data->sbase + WBCIR_REG_SP3_BGDL);
|
|
||||||
break;
|
|
||||||
case IR_PROTOCOL_NEC:
|
|
||||||
outb(0x69, data->sbase + WBCIR_REG_SP3_BGDL);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
outb(0x00, data->sbase + WBCIR_REG_SP3_BGDH);
|
|
||||||
|
|
||||||
/* Set CEIR mode */
|
|
||||||
wbcir_select_bank(data, WBCIR_BANK_0);
|
|
||||||
outb(0xC0, data->sbase + WBCIR_REG_SP3_MCR);
|
|
||||||
inb(data->sbase + WBCIR_REG_SP3_LSR); /* Clear LSR */
|
|
||||||
inb(data->sbase + WBCIR_REG_SP3_MSR); /* Clear MSR */
|
|
||||||
|
|
||||||
/* Disable RX demod, run-length encoding/decoding, set freq span */
|
|
||||||
wbcir_select_bank(data, WBCIR_BANK_7);
|
|
||||||
outb(0x10, data->sbase + WBCIR_REG_SP3_RCCFG);
|
|
||||||
|
|
||||||
/* Disable timer */
|
|
||||||
wbcir_select_bank(data, WBCIR_BANK_4);
|
|
||||||
outb(0x00, data->sbase + WBCIR_REG_SP3_IRCR1);
|
|
||||||
|
|
||||||
/* Enable MSR interrupt, Clear AUX_IRX */
|
|
||||||
wbcir_select_bank(data, WBCIR_BANK_5);
|
|
||||||
outb(0x00, data->sbase + WBCIR_REG_SP3_IRCR2);
|
|
||||||
|
|
||||||
/* Disable CRC */
|
|
||||||
wbcir_select_bank(data, WBCIR_BANK_6);
|
|
||||||
outb(0x20, data->sbase + WBCIR_REG_SP3_IRCR3);
|
|
||||||
|
|
||||||
/* Set RX/TX (de)modulation freq, not really used */
|
|
||||||
wbcir_select_bank(data, WBCIR_BANK_7);
|
|
||||||
outb(0xF2, data->sbase + WBCIR_REG_SP3_IRRXDC);
|
|
||||||
outb(0x69, data->sbase + WBCIR_REG_SP3_IRTXMC);
|
|
||||||
|
|
||||||
/* Set invert and pin direction */
|
|
||||||
if (invert)
|
|
||||||
outb(0x10, data->sbase + WBCIR_REG_SP3_IRCFG4);
|
|
||||||
else
|
|
||||||
outb(0x00, data->sbase + WBCIR_REG_SP3_IRCFG4);
|
|
||||||
|
|
||||||
/* Set FIFO thresholds (RX = 8, TX = 3), reset RX/TX */
|
|
||||||
wbcir_select_bank(data, WBCIR_BANK_0);
|
|
||||||
outb(0x97, data->sbase + WBCIR_REG_SP3_FCR);
|
|
||||||
|
|
||||||
/* Clear AUX status bits */
|
|
||||||
outb(0xE0, data->sbase + WBCIR_REG_SP3_ASCR);
|
|
||||||
|
|
||||||
/* Enable interrupts */
|
|
||||||
outb(WBCIR_IRQ_RX | WBCIR_IRQ_ERR, data->sbase + WBCIR_REG_SP3_IER);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -68,10 +68,6 @@ module_param(post_interrupt_delay, int, 0644);
|
||||||
MODULE_PARM_DESC(post_interrupt_delay,
|
MODULE_PARM_DESC(post_interrupt_delay,
|
||||||
"delay (ms) before recal after recal interrupt detected");
|
"delay (ms) before recal after recal interrupt detected");
|
||||||
|
|
||||||
static int autorecal = 1;
|
|
||||||
module_param(autorecal, int, 0644);
|
|
||||||
MODULE_PARM_DESC(autorecal, "enable recalibration in the driver");
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* When the touchpad gets ultra-sensitive, one can keep their finger 1/2"
|
* When the touchpad gets ultra-sensitive, one can keep their finger 1/2"
|
||||||
* above the pad and still have it send packets. This causes a jump cursor
|
* above the pad and still have it send packets. This causes a jump cursor
|
||||||
|
|
|
||||||
|
|
@ -186,7 +186,7 @@ static void __devexit pcips2_remove(struct pci_dev *dev)
|
||||||
pci_disable_device(dev);
|
pci_disable_device(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct pci_device_id pcips2_ids[] = {
|
static const struct pci_device_id pcips2_ids[] = {
|
||||||
{
|
{
|
||||||
.vendor = 0x14f2, /* MOBILITY */
|
.vendor = 0x14f2, /* MOBILITY */
|
||||||
.device = 0x0123, /* Keyboard */
|
.device = 0x0123, /* Keyboard */
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,8 @@
|
||||||
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
|
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||||
|
|
||||||
#include <linux/stddef.h>
|
#include <linux/stddef.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/serio.h>
|
#include <linux/serio.h>
|
||||||
|
|
@ -119,9 +121,8 @@ static int serio_bind_driver(struct serio *serio, struct serio_driver *drv)
|
||||||
|
|
||||||
error = device_bind_driver(&serio->dev);
|
error = device_bind_driver(&serio->dev);
|
||||||
if (error) {
|
if (error) {
|
||||||
printk(KERN_WARNING
|
dev_warn(&serio->dev,
|
||||||
"serio: device_bind_driver() failed "
|
"device_bind_driver() failed for %s (%s) and %s, error: %d\n",
|
||||||
"for %s (%s) and %s, error: %d\n",
|
|
||||||
serio->phys, serio->name,
|
serio->phys, serio->name,
|
||||||
drv->description, error);
|
drv->description, error);
|
||||||
serio_disconnect_driver(serio);
|
serio_disconnect_driver(serio);
|
||||||
|
|
@ -138,8 +139,8 @@ static void serio_find_driver(struct serio *serio)
|
||||||
|
|
||||||
error = device_attach(&serio->dev);
|
error = device_attach(&serio->dev);
|
||||||
if (error < 0)
|
if (error < 0)
|
||||||
printk(KERN_WARNING
|
dev_warn(&serio->dev,
|
||||||
"serio: device_attach() failed for %s (%s), error: %d\n",
|
"device_attach() failed for %s (%s), error: %d\n",
|
||||||
serio->phys, serio->name, error);
|
serio->phys, serio->name, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -194,16 +195,13 @@ static int serio_queue_event(void *object, struct module *owner,
|
||||||
|
|
||||||
event = kmalloc(sizeof(struct serio_event), GFP_ATOMIC);
|
event = kmalloc(sizeof(struct serio_event), GFP_ATOMIC);
|
||||||
if (!event) {
|
if (!event) {
|
||||||
printk(KERN_ERR
|
pr_err("Not enough memory to queue event %d\n", event_type);
|
||||||
"serio: Not enough memory to queue event %d\n",
|
|
||||||
event_type);
|
|
||||||
retval = -ENOMEM;
|
retval = -ENOMEM;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!try_module_get(owner)) {
|
if (!try_module_get(owner)) {
|
||||||
printk(KERN_WARNING
|
pr_warning("Can't get module reference, dropping event %d\n",
|
||||||
"serio: Can't get module reference, dropping event %d\n",
|
|
||||||
event_type);
|
event_type);
|
||||||
kfree(event);
|
kfree(event);
|
||||||
retval = -EINVAL;
|
retval = -EINVAL;
|
||||||
|
|
@ -230,14 +228,12 @@ static void serio_free_event(struct serio_event *event)
|
||||||
|
|
||||||
static void serio_remove_duplicate_events(struct serio_event *event)
|
static void serio_remove_duplicate_events(struct serio_event *event)
|
||||||
{
|
{
|
||||||
struct list_head *node, *next;
|
struct serio_event *e, *next;
|
||||||
struct serio_event *e;
|
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
spin_lock_irqsave(&serio_event_lock, flags);
|
spin_lock_irqsave(&serio_event_lock, flags);
|
||||||
|
|
||||||
list_for_each_safe(node, next, &serio_event_list) {
|
list_for_each_entry_safe(e, next, &serio_event_list, node) {
|
||||||
e = list_entry(node, struct serio_event, node);
|
|
||||||
if (event->object == e->object) {
|
if (event->object == e->object) {
|
||||||
/*
|
/*
|
||||||
* If this event is of different type we should not
|
* If this event is of different type we should not
|
||||||
|
|
@ -247,7 +243,7 @@ static void serio_remove_duplicate_events(struct serio_event *event)
|
||||||
if (event->type != e->type)
|
if (event->type != e->type)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
list_del_init(node);
|
list_del_init(&e->node);
|
||||||
serio_free_event(e);
|
serio_free_event(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -258,23 +254,18 @@ static void serio_remove_duplicate_events(struct serio_event *event)
|
||||||
|
|
||||||
static struct serio_event *serio_get_event(void)
|
static struct serio_event *serio_get_event(void)
|
||||||
{
|
{
|
||||||
struct serio_event *event;
|
struct serio_event *event = NULL;
|
||||||
struct list_head *node;
|
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
spin_lock_irqsave(&serio_event_lock, flags);
|
spin_lock_irqsave(&serio_event_lock, flags);
|
||||||
|
|
||||||
if (list_empty(&serio_event_list)) {
|
if (!list_empty(&serio_event_list)) {
|
||||||
spin_unlock_irqrestore(&serio_event_lock, flags);
|
event = list_first_entry(&serio_event_list,
|
||||||
return NULL;
|
struct serio_event, node);
|
||||||
|
list_del_init(&event->node);
|
||||||
}
|
}
|
||||||
|
|
||||||
node = serio_event_list.next;
|
|
||||||
event = list_entry(node, struct serio_event, node);
|
|
||||||
list_del_init(node);
|
|
||||||
|
|
||||||
spin_unlock_irqrestore(&serio_event_lock, flags);
|
spin_unlock_irqrestore(&serio_event_lock, flags);
|
||||||
|
|
||||||
return event;
|
return event;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -287,6 +278,7 @@ static void serio_handle_event(void)
|
||||||
while ((event = serio_get_event())) {
|
while ((event = serio_get_event())) {
|
||||||
|
|
||||||
switch (event->type) {
|
switch (event->type) {
|
||||||
|
|
||||||
case SERIO_REGISTER_PORT:
|
case SERIO_REGISTER_PORT:
|
||||||
serio_add_port(event->object);
|
serio_add_port(event->object);
|
||||||
break;
|
break;
|
||||||
|
|
@ -307,9 +299,6 @@ static void serio_handle_event(void)
|
||||||
case SERIO_ATTACH_DRIVER:
|
case SERIO_ATTACH_DRIVER:
|
||||||
serio_attach_driver(event->object);
|
serio_attach_driver(event->object);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
serio_remove_duplicate_events(event);
|
serio_remove_duplicate_events(event);
|
||||||
|
|
@ -325,16 +314,14 @@ static void serio_handle_event(void)
|
||||||
*/
|
*/
|
||||||
static void serio_remove_pending_events(void *object)
|
static void serio_remove_pending_events(void *object)
|
||||||
{
|
{
|
||||||
struct list_head *node, *next;
|
struct serio_event *event, *next;
|
||||||
struct serio_event *event;
|
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
spin_lock_irqsave(&serio_event_lock, flags);
|
spin_lock_irqsave(&serio_event_lock, flags);
|
||||||
|
|
||||||
list_for_each_safe(node, next, &serio_event_list) {
|
list_for_each_entry_safe(event, next, &serio_event_list, node) {
|
||||||
event = list_entry(node, struct serio_event, node);
|
|
||||||
if (event->object == object) {
|
if (event->object == object) {
|
||||||
list_del_init(node);
|
list_del_init(&event->node);
|
||||||
serio_free_event(event);
|
serio_free_event(event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -380,7 +367,6 @@ static int serio_thread(void *nothing)
|
||||||
kthread_should_stop() || !list_empty(&serio_event_list));
|
kthread_should_stop() || !list_empty(&serio_event_list));
|
||||||
} while (!kthread_should_stop());
|
} while (!kthread_should_stop());
|
||||||
|
|
||||||
printk(KERN_DEBUG "serio: kseriod exiting\n");
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -445,6 +431,11 @@ static struct attribute_group serio_id_attr_group = {
|
||||||
.attrs = serio_device_id_attrs,
|
.attrs = serio_device_id_attrs,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct attribute_group *serio_device_attr_groups[] = {
|
||||||
|
&serio_id_attr_group,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
static ssize_t serio_rebind_driver(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
|
static ssize_t serio_rebind_driver(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
|
||||||
{
|
{
|
||||||
struct serio *serio = to_serio_port(dev);
|
struct serio *serio = to_serio_port(dev);
|
||||||
|
|
@ -532,6 +523,7 @@ static void serio_init_port(struct serio *serio)
|
||||||
(long)atomic_inc_return(&serio_no) - 1);
|
(long)atomic_inc_return(&serio_no) - 1);
|
||||||
serio->dev.bus = &serio_bus;
|
serio->dev.bus = &serio_bus;
|
||||||
serio->dev.release = serio_release_port;
|
serio->dev.release = serio_release_port;
|
||||||
|
serio->dev.groups = serio_device_attr_groups;
|
||||||
if (serio->parent) {
|
if (serio->parent) {
|
||||||
serio->dev.parent = &serio->parent->dev;
|
serio->dev.parent = &serio->parent->dev;
|
||||||
serio->depth = serio->parent->depth + 1;
|
serio->depth = serio->parent->depth + 1;
|
||||||
|
|
@ -555,21 +547,15 @@ static void serio_add_port(struct serio *serio)
|
||||||
}
|
}
|
||||||
|
|
||||||
list_add_tail(&serio->node, &serio_list);
|
list_add_tail(&serio->node, &serio_list);
|
||||||
|
|
||||||
if (serio->start)
|
if (serio->start)
|
||||||
serio->start(serio);
|
serio->start(serio);
|
||||||
|
|
||||||
error = device_add(&serio->dev);
|
error = device_add(&serio->dev);
|
||||||
if (error)
|
if (error)
|
||||||
printk(KERN_ERR
|
dev_err(&serio->dev,
|
||||||
"serio: device_add() failed for %s (%s), error: %d\n",
|
"device_add() failed for %s (%s), error: %d\n",
|
||||||
serio->phys, serio->name, error);
|
serio->phys, serio->name, error);
|
||||||
else {
|
|
||||||
serio->registered = true;
|
|
||||||
error = sysfs_create_group(&serio->dev.kobj, &serio_id_attr_group);
|
|
||||||
if (error)
|
|
||||||
printk(KERN_ERR
|
|
||||||
"serio: sysfs_create_group() failed for %s (%s), error: %d\n",
|
|
||||||
serio->phys, serio->name, error);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -596,11 +582,8 @@ static void serio_destroy_port(struct serio *serio)
|
||||||
serio->parent = NULL;
|
serio->parent = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (serio->registered) {
|
if (device_is_registered(&serio->dev))
|
||||||
sysfs_remove_group(&serio->dev.kobj, &serio_id_attr_group);
|
|
||||||
device_del(&serio->dev);
|
device_del(&serio->dev);
|
||||||
serio->registered = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
list_del_init(&serio->node);
|
list_del_init(&serio->node);
|
||||||
serio_remove_pending_events(serio);
|
serio_remove_pending_events(serio);
|
||||||
|
|
@ -798,8 +781,7 @@ static void serio_attach_driver(struct serio_driver *drv)
|
||||||
|
|
||||||
error = driver_attach(&drv->driver);
|
error = driver_attach(&drv->driver);
|
||||||
if (error)
|
if (error)
|
||||||
printk(KERN_WARNING
|
pr_warning("driver_attach() failed for %s with error %d\n",
|
||||||
"serio: driver_attach() failed for %s with error %d\n",
|
|
||||||
drv->driver.name, error);
|
drv->driver.name, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -820,8 +802,7 @@ int __serio_register_driver(struct serio_driver *drv, struct module *owner, cons
|
||||||
|
|
||||||
error = driver_register(&drv->driver);
|
error = driver_register(&drv->driver);
|
||||||
if (error) {
|
if (error) {
|
||||||
printk(KERN_ERR
|
pr_err("driver_register() failed for %s, error: %d\n",
|
||||||
"serio: driver_register() failed for %s, error: %d\n",
|
|
||||||
drv->driver.name, error);
|
drv->driver.name, error);
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
@ -987,7 +968,7 @@ irqreturn_t serio_interrupt(struct serio *serio,
|
||||||
|
|
||||||
if (likely(serio->drv)) {
|
if (likely(serio->drv)) {
|
||||||
ret = serio->drv->interrupt(serio, data, dfl);
|
ret = serio->drv->interrupt(serio, data, dfl);
|
||||||
} else if (!dfl && serio->registered) {
|
} else if (!dfl && device_is_registered(&serio->dev)) {
|
||||||
serio_rescan(serio);
|
serio_rescan(serio);
|
||||||
ret = IRQ_HANDLED;
|
ret = IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
|
|
@ -1018,7 +999,7 @@ static int __init serio_init(void)
|
||||||
|
|
||||||
error = bus_register(&serio_bus);
|
error = bus_register(&serio_bus);
|
||||||
if (error) {
|
if (error) {
|
||||||
printk(KERN_ERR "serio: failed to register serio bus, error: %d\n", error);
|
pr_err("Failed to register serio bus, error: %d\n", error);
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1026,7 +1007,7 @@ static int __init serio_init(void)
|
||||||
if (IS_ERR(serio_task)) {
|
if (IS_ERR(serio_task)) {
|
||||||
bus_unregister(&serio_bus);
|
bus_unregister(&serio_bus);
|
||||||
error = PTR_ERR(serio_task);
|
error = PTR_ERR(serio_task);
|
||||||
printk(KERN_ERR "serio: Failed to start kseriod, error: %d\n", error);
|
pr_err("Failed to start kseriod, error: %d\n", error);
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -270,7 +270,7 @@ static int __devinit xps2_of_probe(struct of_device *ofdev,
|
||||||
drvdata->irq = r_irq.start;
|
drvdata->irq = r_irq.start;
|
||||||
|
|
||||||
phys_addr = r_mem.start;
|
phys_addr = r_mem.start;
|
||||||
remap_size = r_mem.end - r_mem.start + 1;
|
remap_size = resource_size(&r_mem);
|
||||||
if (!request_mem_region(phys_addr, remap_size, DRIVER_NAME)) {
|
if (!request_mem_region(phys_addr, remap_size, DRIVER_NAME)) {
|
||||||
dev_err(dev, "Couldn't lock memory region at 0x%08llX\n",
|
dev_err(dev, "Couldn't lock memory region at 0x%08llX\n",
|
||||||
(unsigned long long)phys_addr);
|
(unsigned long long)phys_addr);
|
||||||
|
|
@ -344,7 +344,7 @@ static int __devexit xps2_of_remove(struct of_device *of_dev)
|
||||||
if (of_address_to_resource(of_dev->node, 0, &r_mem))
|
if (of_address_to_resource(of_dev->node, 0, &r_mem))
|
||||||
dev_err(dev, "invalid address\n");
|
dev_err(dev, "invalid address\n");
|
||||||
else
|
else
|
||||||
release_mem_region(r_mem.start, r_mem.end - r_mem.start + 1);
|
release_mem_region(r_mem.start, resource_size(&r_mem));
|
||||||
|
|
||||||
kfree(drvdata);
|
kfree(drvdata);
|
||||||
|
|
||||||
|
|
@ -354,7 +354,7 @@ static int __devexit xps2_of_remove(struct of_device *of_dev)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Match table for of_platform binding */
|
/* Match table for of_platform binding */
|
||||||
static struct of_device_id xps2_of_match[] __devinitdata = {
|
static const struct of_device_id xps2_of_match[] __devinitconst = {
|
||||||
{ .compatible = "xlnx,xps-ps2-1.00.a", },
|
{ .compatible = "xlnx,xps-ps2-1.00.a", },
|
||||||
{ /* end of list */ },
|
{ /* end of list */ },
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -92,7 +92,7 @@ Scott Hill shill@gtcocalcomp.com
|
||||||
/* DATA STRUCTURES */
|
/* DATA STRUCTURES */
|
||||||
|
|
||||||
/* Device table */
|
/* Device table */
|
||||||
static struct usb_device_id gtco_usbid_table [] = {
|
static const struct usb_device_id gtco_usbid_table[] = {
|
||||||
{ USB_DEVICE(VENDOR_ID_GTCO, PID_400) },
|
{ USB_DEVICE(VENDOR_ID_GTCO, PID_400) },
|
||||||
{ USB_DEVICE(VENDOR_ID_GTCO, PID_401) },
|
{ USB_DEVICE(VENDOR_ID_GTCO, PID_401) },
|
||||||
{ USB_DEVICE(VENDOR_ID_GTCO, PID_1000) },
|
{ USB_DEVICE(VENDOR_ID_GTCO, PID_1000) },
|
||||||
|
|
|
||||||
|
|
@ -85,6 +85,7 @@
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
|
#include <linux/mod_devicetable.h>
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/usb/input.h>
|
#include <linux/usb/input.h>
|
||||||
#include <asm/unaligned.h>
|
#include <asm/unaligned.h>
|
||||||
|
|
@ -120,6 +121,8 @@ struct wacom_combo {
|
||||||
struct urb *urb;
|
struct urb *urb;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
extern const struct usb_device_id wacom_ids[];
|
||||||
|
|
||||||
extern int wacom_wac_irq(struct wacom_wac * wacom_wac, void * wcombo);
|
extern int wacom_wac_irq(struct wacom_wac * wacom_wac, void * wcombo);
|
||||||
extern void wacom_report_abs(void *wcombo, unsigned int abs_type, int abs_data);
|
extern void wacom_report_abs(void *wcombo, unsigned int abs_type, int abs_data);
|
||||||
extern void wacom_report_rel(void *wcombo, unsigned int rel_type, int rel_data);
|
extern void wacom_report_rel(void *wcombo, unsigned int rel_type, int rel_data);
|
||||||
|
|
@ -142,7 +145,5 @@ extern void input_dev_mo(struct input_dev *input_dev, struct wacom_wac *wacom_wa
|
||||||
extern void input_dev_bee(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
|
extern void input_dev_bee(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
|
||||||
extern __u16 wacom_le16_to_cpu(unsigned char *data);
|
extern __u16 wacom_le16_to_cpu(unsigned char *data);
|
||||||
extern __u16 wacom_be16_to_cpu(unsigned char *data);
|
extern __u16 wacom_be16_to_cpu(unsigned char *data);
|
||||||
extern struct wacom_features *get_wacom_feature(const struct usb_device_id *id);
|
|
||||||
extern const struct usb_device_id *get_device_table(void);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -211,7 +211,8 @@ void input_dev_g(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
|
||||||
input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_TOOL_RUBBER) |
|
input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_TOOL_RUBBER) |
|
||||||
BIT_MASK(BTN_TOOL_PEN) | BIT_MASK(BTN_STYLUS) |
|
BIT_MASK(BTN_TOOL_PEN) | BIT_MASK(BTN_STYLUS) |
|
||||||
BIT_MASK(BTN_TOOL_MOUSE) | BIT_MASK(BTN_STYLUS2);
|
BIT_MASK(BTN_TOOL_MOUSE) | BIT_MASK(BTN_STYLUS2);
|
||||||
input_set_abs_params(input_dev, ABS_DISTANCE, 0, wacom_wac->features->distance_max, 0, 0);
|
input_set_abs_params(input_dev, ABS_DISTANCE,
|
||||||
|
0, wacom_wac->features.distance_max, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void input_dev_i3s(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
|
void input_dev_i3s(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
|
||||||
|
|
@ -261,7 +262,8 @@ void input_dev_i(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
|
||||||
BIT_MASK(BTN_TOOL_MOUSE) | BIT_MASK(BTN_TOOL_BRUSH) |
|
BIT_MASK(BTN_TOOL_MOUSE) | BIT_MASK(BTN_TOOL_BRUSH) |
|
||||||
BIT_MASK(BTN_TOOL_PENCIL) | BIT_MASK(BTN_TOOL_AIRBRUSH) |
|
BIT_MASK(BTN_TOOL_PENCIL) | BIT_MASK(BTN_TOOL_AIRBRUSH) |
|
||||||
BIT_MASK(BTN_TOOL_LENS) | BIT_MASK(BTN_STYLUS2);
|
BIT_MASK(BTN_TOOL_LENS) | BIT_MASK(BTN_STYLUS2);
|
||||||
input_set_abs_params(input_dev, ABS_DISTANCE, 0, wacom_wac->features->distance_max, 0, 0);
|
input_set_abs_params(input_dev, ABS_DISTANCE,
|
||||||
|
0, wacom_wac->features.distance_max, 0, 0);
|
||||||
input_set_abs_params(input_dev, ABS_WHEEL, 0, 1023, 0, 0);
|
input_set_abs_params(input_dev, ABS_WHEEL, 0, 1023, 0, 0);
|
||||||
input_set_abs_params(input_dev, ABS_TILT_X, 0, 127, 0, 0);
|
input_set_abs_params(input_dev, ABS_TILT_X, 0, 127, 0, 0);
|
||||||
input_set_abs_params(input_dev, ABS_TILT_Y, 0, 127, 0, 0);
|
input_set_abs_params(input_dev, ABS_TILT_Y, 0, 127, 0, 0);
|
||||||
|
|
@ -282,17 +284,19 @@ void input_dev_pt(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
|
||||||
|
|
||||||
void input_dev_tpc(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
|
void input_dev_tpc(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
|
||||||
{
|
{
|
||||||
if (wacom_wac->features->device_type == BTN_TOOL_DOUBLETAP ||
|
struct wacom_features *features = &wacom_wac->features;
|
||||||
wacom_wac->features->device_type == BTN_TOOL_TRIPLETAP) {
|
|
||||||
input_set_abs_params(input_dev, ABS_RX, 0, wacom_wac->features->x_phy, 0, 0);
|
if (features->device_type == BTN_TOOL_DOUBLETAP ||
|
||||||
input_set_abs_params(input_dev, ABS_RY, 0, wacom_wac->features->y_phy, 0, 0);
|
features->device_type == BTN_TOOL_TRIPLETAP) {
|
||||||
input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_TOOL_DOUBLETAP);
|
input_set_abs_params(input_dev, ABS_RX, 0, features->x_phy, 0, 0);
|
||||||
|
input_set_abs_params(input_dev, ABS_RY, 0, features->y_phy, 0, 0);
|
||||||
|
__set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void input_dev_tpc2fg(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
|
void input_dev_tpc2fg(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
|
||||||
{
|
{
|
||||||
if (wacom_wac->features->device_type == BTN_TOOL_TRIPLETAP) {
|
if (wacom_wac->features.device_type == BTN_TOOL_TRIPLETAP) {
|
||||||
input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_TOOL_TRIPLETAP);
|
input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_TOOL_TRIPLETAP);
|
||||||
input_dev->evbit[0] |= BIT_MASK(EV_MSC);
|
input_dev->evbit[0] |= BIT_MASK(EV_MSC);
|
||||||
input_dev->mscbit[0] |= BIT_MASK(MSC_SERIAL);
|
input_dev->mscbit[0] |= BIT_MASK(MSC_SERIAL);
|
||||||
|
|
@ -532,21 +536,38 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
|
||||||
struct wacom_wac *wacom_wac;
|
struct wacom_wac *wacom_wac;
|
||||||
struct wacom_features *features;
|
struct wacom_features *features;
|
||||||
struct input_dev *input_dev;
|
struct input_dev *input_dev;
|
||||||
int error = -ENOMEM;
|
int error;
|
||||||
|
|
||||||
|
if (!id->driver_info)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
wacom = kzalloc(sizeof(struct wacom), GFP_KERNEL);
|
wacom = kzalloc(sizeof(struct wacom), GFP_KERNEL);
|
||||||
wacom_wac = kzalloc(sizeof(struct wacom_wac), GFP_KERNEL);
|
wacom_wac = kzalloc(sizeof(struct wacom_wac), GFP_KERNEL);
|
||||||
input_dev = input_allocate_device();
|
input_dev = input_allocate_device();
|
||||||
if (!wacom || !input_dev || !wacom_wac)
|
if (!wacom || !input_dev || !wacom_wac) {
|
||||||
|
error = -ENOMEM;
|
||||||
goto fail1;
|
goto fail1;
|
||||||
|
}
|
||||||
|
|
||||||
wacom_wac->data = usb_buffer_alloc(dev, WACOM_PKGLEN_MAX, GFP_KERNEL, &wacom->data_dma);
|
wacom_wac->features = *((struct wacom_features *)id->driver_info);
|
||||||
if (!wacom_wac->data)
|
features = &wacom_wac->features;
|
||||||
|
if (features->pktlen > WACOM_PKGLEN_MAX) {
|
||||||
|
error = -EINVAL;
|
||||||
goto fail1;
|
goto fail1;
|
||||||
|
}
|
||||||
|
|
||||||
|
wacom_wac->data = usb_buffer_alloc(dev, WACOM_PKGLEN_MAX,
|
||||||
|
GFP_KERNEL, &wacom->data_dma);
|
||||||
|
if (!wacom_wac->data) {
|
||||||
|
error = -ENOMEM;
|
||||||
|
goto fail1;
|
||||||
|
}
|
||||||
|
|
||||||
wacom->irq = usb_alloc_urb(0, GFP_KERNEL);
|
wacom->irq = usb_alloc_urb(0, GFP_KERNEL);
|
||||||
if (!wacom->irq)
|
if (!wacom->irq) {
|
||||||
|
error = -ENOMEM;
|
||||||
goto fail2;
|
goto fail2;
|
||||||
|
}
|
||||||
|
|
||||||
wacom->usbdev = dev;
|
wacom->usbdev = dev;
|
||||||
wacom->dev = input_dev;
|
wacom->dev = input_dev;
|
||||||
|
|
@ -555,11 +576,6 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
|
||||||
usb_make_path(dev, wacom->phys, sizeof(wacom->phys));
|
usb_make_path(dev, wacom->phys, sizeof(wacom->phys));
|
||||||
strlcat(wacom->phys, "/input0", sizeof(wacom->phys));
|
strlcat(wacom->phys, "/input0", sizeof(wacom->phys));
|
||||||
|
|
||||||
wacom_wac->features = features = get_wacom_feature(id);
|
|
||||||
BUG_ON(features->pktlen > WACOM_PKGLEN_MAX);
|
|
||||||
|
|
||||||
input_dev->name = wacom_wac->features->name;
|
|
||||||
wacom->wacom_wac = wacom_wac;
|
|
||||||
usb_to_input_id(dev, &input_dev->id);
|
usb_to_input_id(dev, &input_dev->id);
|
||||||
|
|
||||||
input_dev->dev.parent = &intf->dev;
|
input_dev->dev.parent = &intf->dev;
|
||||||
|
|
@ -576,6 +592,19 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
|
||||||
if (error)
|
if (error)
|
||||||
goto fail2;
|
goto fail2;
|
||||||
|
|
||||||
|
strlcpy(wacom_wac->name, features->name, sizeof(wacom_wac->name));
|
||||||
|
|
||||||
|
if (features->type == TABLETPC || features->type == TABLETPC2FG) {
|
||||||
|
/* Append the device type to the name */
|
||||||
|
strlcat(wacom_wac->name,
|
||||||
|
features->device_type == BTN_TOOL_PEN ?
|
||||||
|
" Pen" : " Finger",
|
||||||
|
sizeof(wacom_wac->name));
|
||||||
|
}
|
||||||
|
|
||||||
|
input_dev->name = wacom_wac->name;
|
||||||
|
wacom->wacom_wac = wacom_wac;
|
||||||
|
|
||||||
input_dev->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
|
input_dev->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
|
||||||
input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_TOUCH);
|
input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_TOUCH);
|
||||||
|
|
||||||
|
|
@ -640,7 +669,7 @@ static int wacom_suspend(struct usb_interface *intf, pm_message_t message)
|
||||||
static int wacom_resume(struct usb_interface *intf)
|
static int wacom_resume(struct usb_interface *intf)
|
||||||
{
|
{
|
||||||
struct wacom *wacom = usb_get_intfdata(intf);
|
struct wacom *wacom = usb_get_intfdata(intf);
|
||||||
struct wacom_features *features = wacom->wacom_wac->features;
|
struct wacom_features *features = &wacom->wacom_wac->features;
|
||||||
int rv;
|
int rv;
|
||||||
|
|
||||||
mutex_lock(&wacom->lock);
|
mutex_lock(&wacom->lock);
|
||||||
|
|
@ -663,6 +692,7 @@ static int wacom_reset_resume(struct usb_interface *intf)
|
||||||
|
|
||||||
static struct usb_driver wacom_driver = {
|
static struct usb_driver wacom_driver = {
|
||||||
.name = "wacom",
|
.name = "wacom",
|
||||||
|
.id_table = wacom_ids,
|
||||||
.probe = wacom_probe,
|
.probe = wacom_probe,
|
||||||
.disconnect = wacom_disconnect,
|
.disconnect = wacom_disconnect,
|
||||||
.suspend = wacom_suspend,
|
.suspend = wacom_suspend,
|
||||||
|
|
@ -674,7 +704,7 @@ static struct usb_driver wacom_driver = {
|
||||||
static int __init wacom_init(void)
|
static int __init wacom_init(void)
|
||||||
{
|
{
|
||||||
int result;
|
int result;
|
||||||
wacom_driver.id_table = get_device_table();
|
|
||||||
result = usb_register(&wacom_driver);
|
result = usb_register(&wacom_driver);
|
||||||
if (result == 0)
|
if (result == 0)
|
||||||
printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
|
printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
|
||||||
|
|
|
||||||
|
|
@ -55,6 +55,7 @@ static int wacom_penpartner_irq(struct wacom_wac *wacom, void *wcombo)
|
||||||
|
|
||||||
static int wacom_pl_irq(struct wacom_wac *wacom, void *wcombo)
|
static int wacom_pl_irq(struct wacom_wac *wacom, void *wcombo)
|
||||||
{
|
{
|
||||||
|
struct wacom_features *features = &wacom->features;
|
||||||
unsigned char *data = wacom->data;
|
unsigned char *data = wacom->data;
|
||||||
int prox, pressure;
|
int prox, pressure;
|
||||||
|
|
||||||
|
|
@ -68,9 +69,9 @@ static int wacom_pl_irq(struct wacom_wac *wacom, void *wcombo)
|
||||||
if (prox) {
|
if (prox) {
|
||||||
wacom->id[0] = ERASER_DEVICE_ID;
|
wacom->id[0] = ERASER_DEVICE_ID;
|
||||||
pressure = (signed char)((data[7] << 1) | ((data[4] >> 2) & 1));
|
pressure = (signed char)((data[7] << 1) | ((data[4] >> 2) & 1));
|
||||||
if (wacom->features->pressure_max > 255)
|
if (features->pressure_max > 255)
|
||||||
pressure = (pressure << 1) | ((data[4] >> 6) & 1);
|
pressure = (pressure << 1) | ((data[4] >> 6) & 1);
|
||||||
pressure += (wacom->features->pressure_max + 1) / 2;
|
pressure += (features->pressure_max + 1) / 2;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* if going from out of proximity into proximity select between the eraser
|
* if going from out of proximity into proximity select between the eraser
|
||||||
|
|
@ -152,6 +153,7 @@ static int wacom_ptu_irq(struct wacom_wac *wacom, void *wcombo)
|
||||||
|
|
||||||
static int wacom_graphire_irq(struct wacom_wac *wacom, void *wcombo)
|
static int wacom_graphire_irq(struct wacom_wac *wacom, void *wcombo)
|
||||||
{
|
{
|
||||||
|
struct wacom_features *features = &wacom->features;
|
||||||
unsigned char *data = wacom->data;
|
unsigned char *data = wacom->data;
|
||||||
int x, y, rw;
|
int x, y, rw;
|
||||||
static int penData = 0;
|
static int penData = 0;
|
||||||
|
|
@ -179,8 +181,7 @@ static int wacom_graphire_irq(struct wacom_wac *wacom, void *wcombo)
|
||||||
|
|
||||||
case 2: /* Mouse with wheel */
|
case 2: /* Mouse with wheel */
|
||||||
wacom_report_key(wcombo, BTN_MIDDLE, data[1] & 0x04);
|
wacom_report_key(wcombo, BTN_MIDDLE, data[1] & 0x04);
|
||||||
if (wacom->features->type == WACOM_G4 ||
|
if (features->type == WACOM_G4 || features->type == WACOM_MO) {
|
||||||
wacom->features->type == WACOM_MO) {
|
|
||||||
rw = data[7] & 0x04 ? (data[7] & 0x03)-4 : (data[7] & 0x03);
|
rw = data[7] & 0x04 ? (data[7] & 0x03)-4 : (data[7] & 0x03);
|
||||||
wacom_report_rel(wcombo, REL_WHEEL, -rw);
|
wacom_report_rel(wcombo, REL_WHEEL, -rw);
|
||||||
} else
|
} else
|
||||||
|
|
@ -192,8 +193,7 @@ static int wacom_graphire_irq(struct wacom_wac *wacom, void *wcombo)
|
||||||
wacom->id[0] = CURSOR_DEVICE_ID;
|
wacom->id[0] = CURSOR_DEVICE_ID;
|
||||||
wacom_report_key(wcombo, BTN_LEFT, data[1] & 0x01);
|
wacom_report_key(wcombo, BTN_LEFT, data[1] & 0x01);
|
||||||
wacom_report_key(wcombo, BTN_RIGHT, data[1] & 0x02);
|
wacom_report_key(wcombo, BTN_RIGHT, data[1] & 0x02);
|
||||||
if (wacom->features->type == WACOM_G4 ||
|
if (features->type == WACOM_G4 || features->type == WACOM_MO)
|
||||||
wacom->features->type == WACOM_MO)
|
|
||||||
wacom_report_abs(wcombo, ABS_DISTANCE, data[6] & 0x3f);
|
wacom_report_abs(wcombo, ABS_DISTANCE, data[6] & 0x3f);
|
||||||
else
|
else
|
||||||
wacom_report_abs(wcombo, ABS_DISTANCE, data[7] & 0x3f);
|
wacom_report_abs(wcombo, ABS_DISTANCE, data[7] & 0x3f);
|
||||||
|
|
@ -230,7 +230,7 @@ static int wacom_graphire_irq(struct wacom_wac *wacom, void *wcombo)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* send pad data */
|
/* send pad data */
|
||||||
switch (wacom->features->type) {
|
switch (features->type) {
|
||||||
case WACOM_G4:
|
case WACOM_G4:
|
||||||
if (data[7] & 0xf8) {
|
if (data[7] & 0xf8) {
|
||||||
if (penData) {
|
if (penData) {
|
||||||
|
|
@ -300,11 +300,12 @@ static int wacom_graphire_irq(struct wacom_wac *wacom, void *wcombo)
|
||||||
|
|
||||||
static int wacom_intuos_inout(struct wacom_wac *wacom, void *wcombo)
|
static int wacom_intuos_inout(struct wacom_wac *wacom, void *wcombo)
|
||||||
{
|
{
|
||||||
|
struct wacom_features *features = &wacom->features;
|
||||||
unsigned char *data = wacom->data;
|
unsigned char *data = wacom->data;
|
||||||
int idx = 0;
|
int idx = 0;
|
||||||
|
|
||||||
/* tool number */
|
/* tool number */
|
||||||
if (wacom->features->type == INTUOS)
|
if (features->type == INTUOS)
|
||||||
idx = data[1] & 0x01;
|
idx = data[1] & 0x01;
|
||||||
|
|
||||||
/* Enter report */
|
/* Enter report */
|
||||||
|
|
@ -402,7 +403,7 @@ static int wacom_intuos_inout(struct wacom_wac *wacom, void *wcombo)
|
||||||
wacom_report_key(wcombo, BTN_STYLUS2, 0);
|
wacom_report_key(wcombo, BTN_STYLUS2, 0);
|
||||||
wacom_report_key(wcombo, BTN_TOUCH, 0);
|
wacom_report_key(wcombo, BTN_TOUCH, 0);
|
||||||
wacom_report_abs(wcombo, ABS_WHEEL, 0);
|
wacom_report_abs(wcombo, ABS_WHEEL, 0);
|
||||||
if (wacom->features->type >= INTUOS3S)
|
if (features->type >= INTUOS3S)
|
||||||
wacom_report_abs(wcombo, ABS_Z, 0);
|
wacom_report_abs(wcombo, ABS_Z, 0);
|
||||||
}
|
}
|
||||||
wacom_report_key(wcombo, wacom->tool[idx], 0);
|
wacom_report_key(wcombo, wacom->tool[idx], 0);
|
||||||
|
|
@ -416,13 +417,14 @@ static int wacom_intuos_inout(struct wacom_wac *wacom, void *wcombo)
|
||||||
|
|
||||||
static void wacom_intuos_general(struct wacom_wac *wacom, void *wcombo)
|
static void wacom_intuos_general(struct wacom_wac *wacom, void *wcombo)
|
||||||
{
|
{
|
||||||
|
struct wacom_features *features = &wacom->features;
|
||||||
unsigned char *data = wacom->data;
|
unsigned char *data = wacom->data;
|
||||||
unsigned int t;
|
unsigned int t;
|
||||||
|
|
||||||
/* general pen packet */
|
/* general pen packet */
|
||||||
if ((data[1] & 0xb8) == 0xa0) {
|
if ((data[1] & 0xb8) == 0xa0) {
|
||||||
t = (data[6] << 2) | ((data[7] >> 6) & 3);
|
t = (data[6] << 2) | ((data[7] >> 6) & 3);
|
||||||
if (wacom->features->type >= INTUOS4S && wacom->features->type <= INTUOS4L)
|
if (features->type >= INTUOS4S && features->type <= INTUOS4L)
|
||||||
t = (t << 1) | (data[1] & 1);
|
t = (t << 1) | (data[1] & 1);
|
||||||
wacom_report_abs(wcombo, ABS_PRESSURE, t);
|
wacom_report_abs(wcombo, ABS_PRESSURE, t);
|
||||||
wacom_report_abs(wcombo, ABS_TILT_X,
|
wacom_report_abs(wcombo, ABS_TILT_X,
|
||||||
|
|
@ -446,6 +448,7 @@ static void wacom_intuos_general(struct wacom_wac *wacom, void *wcombo)
|
||||||
|
|
||||||
static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo)
|
static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo)
|
||||||
{
|
{
|
||||||
|
struct wacom_features *features = &wacom->features;
|
||||||
unsigned char *data = wacom->data;
|
unsigned char *data = wacom->data;
|
||||||
unsigned int t;
|
unsigned int t;
|
||||||
int idx = 0, result;
|
int idx = 0, result;
|
||||||
|
|
@ -457,7 +460,7 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* tool number */
|
/* tool number */
|
||||||
if (wacom->features->type == INTUOS)
|
if (features->type == INTUOS)
|
||||||
idx = data[1] & 0x01;
|
idx = data[1] & 0x01;
|
||||||
|
|
||||||
/* pad packets. Works as a second tool and is always in prox */
|
/* pad packets. Works as a second tool and is always in prox */
|
||||||
|
|
@ -466,7 +469,7 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo)
|
||||||
if (wacom->tool[1] != BTN_TOOL_FINGER)
|
if (wacom->tool[1] != BTN_TOOL_FINGER)
|
||||||
wacom->tool[1] = BTN_TOOL_FINGER;
|
wacom->tool[1] = BTN_TOOL_FINGER;
|
||||||
|
|
||||||
if (wacom->features->type >= INTUOS4S && wacom->features->type <= INTUOS4L) {
|
if (features->type >= INTUOS4S && features->type <= INTUOS4L) {
|
||||||
wacom_report_key(wcombo, BTN_0, (data[2] & 0x01));
|
wacom_report_key(wcombo, BTN_0, (data[2] & 0x01));
|
||||||
wacom_report_key(wcombo, BTN_1, (data[3] & 0x01));
|
wacom_report_key(wcombo, BTN_1, (data[3] & 0x01));
|
||||||
wacom_report_key(wcombo, BTN_2, (data[3] & 0x02));
|
wacom_report_key(wcombo, BTN_2, (data[3] & 0x02));
|
||||||
|
|
@ -480,7 +483,7 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo)
|
||||||
/* Out of proximity, clear wheel value. */
|
/* Out of proximity, clear wheel value. */
|
||||||
wacom_report_abs(wcombo, ABS_WHEEL, 0);
|
wacom_report_abs(wcombo, ABS_WHEEL, 0);
|
||||||
}
|
}
|
||||||
if (wacom->features->type != INTUOS4S) {
|
if (features->type != INTUOS4S) {
|
||||||
wacom_report_key(wcombo, BTN_7, (data[3] & 0x40));
|
wacom_report_key(wcombo, BTN_7, (data[3] & 0x40));
|
||||||
wacom_report_key(wcombo, BTN_8, (data[3] & 0x80));
|
wacom_report_key(wcombo, BTN_8, (data[3] & 0x80));
|
||||||
}
|
}
|
||||||
|
|
@ -528,18 +531,20 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* Only large Intuos support Lense Cursor */
|
/* Only large Intuos support Lense Cursor */
|
||||||
if ((wacom->tool[idx] == BTN_TOOL_LENS)
|
if (wacom->tool[idx] == BTN_TOOL_LENS &&
|
||||||
&& ((wacom->features->type == INTUOS3)
|
(features->type == INTUOS3 ||
|
||||||
|| (wacom->features->type == INTUOS3S)
|
features->type == INTUOS3S ||
|
||||||
|| (wacom->features->type == INTUOS4)
|
features->type == INTUOS4 ||
|
||||||
|| (wacom->features->type == INTUOS4S)))
|
features->type == INTUOS4S)) {
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Cintiq doesn't send data when RDY bit isn't set */
|
/* Cintiq doesn't send data when RDY bit isn't set */
|
||||||
if ((wacom->features->type == CINTIQ) && !(data[1] & 0x40))
|
if (features->type == CINTIQ && !(data[1] & 0x40))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (wacom->features->type >= INTUOS3S) {
|
if (features->type >= INTUOS3S) {
|
||||||
wacom_report_abs(wcombo, ABS_X, (data[2] << 9) | (data[3] << 1) | ((data[9] >> 1) & 1));
|
wacom_report_abs(wcombo, ABS_X, (data[2] << 9) | (data[3] << 1) | ((data[9] >> 1) & 1));
|
||||||
wacom_report_abs(wcombo, ABS_Y, (data[4] << 9) | (data[5] << 1) | (data[9] & 1));
|
wacom_report_abs(wcombo, ABS_Y, (data[4] << 9) | (data[5] << 1) | (data[9] & 1));
|
||||||
wacom_report_abs(wcombo, ABS_DISTANCE, ((data[9] >> 2) & 0x3f));
|
wacom_report_abs(wcombo, ABS_DISTANCE, ((data[9] >> 2) & 0x3f));
|
||||||
|
|
@ -557,7 +562,7 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo)
|
||||||
|
|
||||||
if (data[1] & 0x02) {
|
if (data[1] & 0x02) {
|
||||||
/* Rotation packet */
|
/* Rotation packet */
|
||||||
if (wacom->features->type >= INTUOS3S) {
|
if (features->type >= INTUOS3S) {
|
||||||
/* I3 marker pen rotation */
|
/* I3 marker pen rotation */
|
||||||
t = (data[6] << 3) | ((data[7] >> 5) & 7);
|
t = (data[6] << 3) | ((data[7] >> 5) & 7);
|
||||||
t = (data[7] & 0x20) ? ((t > 900) ? ((t-1) / 2 - 1350) :
|
t = (data[7] & 0x20) ? ((t > 900) ? ((t-1) / 2 - 1350) :
|
||||||
|
|
@ -570,7 +575,7 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo)
|
||||||
((t - 1) / 2) : -t / 2);
|
((t - 1) / 2) : -t / 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (!(data[1] & 0x10) && wacom->features->type < INTUOS3S) {
|
} else if (!(data[1] & 0x10) && features->type < INTUOS3S) {
|
||||||
/* 4D mouse packet */
|
/* 4D mouse packet */
|
||||||
wacom_report_key(wcombo, BTN_LEFT, data[8] & 0x01);
|
wacom_report_key(wcombo, BTN_LEFT, data[8] & 0x01);
|
||||||
wacom_report_key(wcombo, BTN_MIDDLE, data[8] & 0x02);
|
wacom_report_key(wcombo, BTN_MIDDLE, data[8] & 0x02);
|
||||||
|
|
@ -583,7 +588,7 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo)
|
||||||
|
|
||||||
} else if (wacom->tool[idx] == BTN_TOOL_MOUSE) {
|
} else if (wacom->tool[idx] == BTN_TOOL_MOUSE) {
|
||||||
/* I4 mouse */
|
/* I4 mouse */
|
||||||
if (wacom->features->type >= INTUOS4S && wacom->features->type <= INTUOS4L) {
|
if (features->type >= INTUOS4S && features->type <= INTUOS4L) {
|
||||||
wacom_report_key(wcombo, BTN_LEFT, data[6] & 0x01);
|
wacom_report_key(wcombo, BTN_LEFT, data[6] & 0x01);
|
||||||
wacom_report_key(wcombo, BTN_MIDDLE, data[6] & 0x02);
|
wacom_report_key(wcombo, BTN_MIDDLE, data[6] & 0x02);
|
||||||
wacom_report_key(wcombo, BTN_RIGHT, data[6] & 0x04);
|
wacom_report_key(wcombo, BTN_RIGHT, data[6] & 0x04);
|
||||||
|
|
@ -604,13 +609,13 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo)
|
||||||
- ((data[8] & 0x02) >> 1));
|
- ((data[8] & 0x02) >> 1));
|
||||||
|
|
||||||
/* I3 2D mouse side buttons */
|
/* I3 2D mouse side buttons */
|
||||||
if (wacom->features->type >= INTUOS3S && wacom->features->type <= INTUOS3L) {
|
if (features->type >= INTUOS3S && features->type <= INTUOS3L) {
|
||||||
wacom_report_key(wcombo, BTN_SIDE, data[8] & 0x40);
|
wacom_report_key(wcombo, BTN_SIDE, data[8] & 0x40);
|
||||||
wacom_report_key(wcombo, BTN_EXTRA, data[8] & 0x20);
|
wacom_report_key(wcombo, BTN_EXTRA, data[8] & 0x20);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if ((wacom->features->type < INTUOS3S || wacom->features->type == INTUOS3L ||
|
} else if ((features->type < INTUOS3S || features->type == INTUOS3L ||
|
||||||
wacom->features->type == INTUOS4L) &&
|
features->type == INTUOS4L) &&
|
||||||
wacom->tool[idx] == BTN_TOOL_LENS) {
|
wacom->tool[idx] == BTN_TOOL_LENS) {
|
||||||
/* Lens cursor packets */
|
/* Lens cursor packets */
|
||||||
wacom_report_key(wcombo, BTN_LEFT, data[8] & 0x01);
|
wacom_report_key(wcombo, BTN_LEFT, data[8] & 0x01);
|
||||||
|
|
@ -718,6 +723,7 @@ static void wacom_tpc_touch_in(struct wacom_wac *wacom, void *wcombo)
|
||||||
|
|
||||||
static int wacom_tpc_irq(struct wacom_wac *wacom, void *wcombo)
|
static int wacom_tpc_irq(struct wacom_wac *wacom, void *wcombo)
|
||||||
{
|
{
|
||||||
|
struct wacom_features *features = &wacom->features;
|
||||||
char *data = wacom->data;
|
char *data = wacom->data;
|
||||||
int prox = 0, pressure, idx = -1;
|
int prox = 0, pressure, idx = -1;
|
||||||
static int stylusInProx, touchInProx = 1, touchOut;
|
static int stylusInProx, touchInProx = 1, touchOut;
|
||||||
|
|
@ -791,7 +797,7 @@ static int wacom_tpc_irq(struct wacom_wac *wacom, void *wcombo)
|
||||||
wacom_report_abs(wcombo, ABS_Y, wacom_le16_to_cpu(&data[4]));
|
wacom_report_abs(wcombo, ABS_Y, wacom_le16_to_cpu(&data[4]));
|
||||||
pressure = ((data[7] & 0x01) << 8) | data[6];
|
pressure = ((data[7] & 0x01) << 8) | data[6];
|
||||||
if (pressure < 0)
|
if (pressure < 0)
|
||||||
pressure = wacom->features->pressure_max + pressure + 1;
|
pressure = features->pressure_max + pressure + 1;
|
||||||
wacom_report_abs(wcombo, ABS_PRESSURE, pressure);
|
wacom_report_abs(wcombo, ABS_PRESSURE, pressure);
|
||||||
wacom_report_key(wcombo, BTN_TOUCH, data[1] & 0x05);
|
wacom_report_key(wcombo, BTN_TOUCH, data[1] & 0x05);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -815,7 +821,7 @@ static int wacom_tpc_irq(struct wacom_wac *wacom, void *wcombo)
|
||||||
|
|
||||||
int wacom_wac_irq(struct wacom_wac *wacom_wac, void *wcombo)
|
int wacom_wac_irq(struct wacom_wac *wacom_wac, void *wcombo)
|
||||||
{
|
{
|
||||||
switch (wacom_wac->features->type) {
|
switch (wacom_wac->features.type) {
|
||||||
case PENPARTNER:
|
case PENPARTNER:
|
||||||
return wacom_penpartner_irq(wacom_wac, wcombo);
|
return wacom_penpartner_irq(wacom_wac, wcombo);
|
||||||
|
|
||||||
|
|
@ -853,7 +859,7 @@ int wacom_wac_irq(struct wacom_wac *wacom_wac, void *wcombo)
|
||||||
|
|
||||||
void wacom_init_input_dev(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
|
void wacom_init_input_dev(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
|
||||||
{
|
{
|
||||||
switch (wacom_wac->features->type) {
|
switch (wacom_wac->features.type) {
|
||||||
case WACOM_MO:
|
case WACOM_MO:
|
||||||
input_dev_mo(input_dev, wacom_wac);
|
input_dev_mo(input_dev, wacom_wac);
|
||||||
case WACOM_G4:
|
case WACOM_G4:
|
||||||
|
|
@ -888,7 +894,7 @@ void wacom_init_input_dev(struct input_dev *input_dev, struct wacom_wac *wacom_w
|
||||||
/* fall through */
|
/* fall through */
|
||||||
case TABLETPC:
|
case TABLETPC:
|
||||||
input_dev_tpc(input_dev, wacom_wac);
|
input_dev_tpc(input_dev, wacom_wac);
|
||||||
if (wacom_wac->features->device_type != BTN_TOOL_PEN)
|
if (wacom_wac->features.device_type != BTN_TOOL_PEN)
|
||||||
break; /* no need to process stylus stuff */
|
break; /* no need to process stylus stuff */
|
||||||
|
|
||||||
/* fall through */
|
/* fall through */
|
||||||
|
|
@ -903,153 +909,201 @@ void wacom_init_input_dev(struct input_dev *input_dev, struct wacom_wac *wacom_w
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct wacom_features wacom_features[] = {
|
static const struct wacom_features wacom_features_0x00 =
|
||||||
{ "Wacom Penpartner", WACOM_PKGLEN_PENPRTN, 5040, 3780, 255, 0, PENPARTNER },
|
{ "Wacom Penpartner", WACOM_PKGLEN_PENPRTN, 5040, 3780, 255, 0, PENPARTNER };
|
||||||
{ "Wacom Graphire", WACOM_PKGLEN_GRAPHIRE, 10206, 7422, 511, 63, GRAPHIRE },
|
static const struct wacom_features wacom_features_0x10 =
|
||||||
{ "Wacom Graphire2 4x5", WACOM_PKGLEN_GRAPHIRE, 10206, 7422, 511, 63, GRAPHIRE },
|
{ "Wacom Graphire", WACOM_PKGLEN_GRAPHIRE, 10206, 7422, 511, 63, GRAPHIRE };
|
||||||
{ "Wacom Graphire2 5x7", WACOM_PKGLEN_GRAPHIRE, 13918, 10206, 511, 63, GRAPHIRE },
|
static const struct wacom_features wacom_features_0x11 =
|
||||||
{ "Wacom Graphire3", WACOM_PKGLEN_GRAPHIRE, 10208, 7424, 511, 63, GRAPHIRE },
|
{ "Wacom Graphire2 4x5", WACOM_PKGLEN_GRAPHIRE, 10206, 7422, 511, 63, GRAPHIRE };
|
||||||
{ "Wacom Graphire3 6x8", WACOM_PKGLEN_GRAPHIRE, 16704, 12064, 511, 63, GRAPHIRE },
|
static const struct wacom_features wacom_features_0x12 =
|
||||||
{ "Wacom Graphire4 4x5", WACOM_PKGLEN_GRAPHIRE, 10208, 7424, 511, 63, WACOM_G4 },
|
{ "Wacom Graphire2 5x7", WACOM_PKGLEN_GRAPHIRE, 13918, 10206, 511, 63, GRAPHIRE };
|
||||||
{ "Wacom Graphire4 6x8", WACOM_PKGLEN_GRAPHIRE, 16704, 12064, 511, 63, WACOM_G4 },
|
static const struct wacom_features wacom_features_0x13 =
|
||||||
{ "Wacom BambooFun 4x5", WACOM_PKGLEN_BBFUN, 14760, 9225, 511, 63, WACOM_MO },
|
{ "Wacom Graphire3", WACOM_PKGLEN_GRAPHIRE, 10208, 7424, 511, 63, GRAPHIRE };
|
||||||
{ "Wacom BambooFun 6x8", WACOM_PKGLEN_BBFUN, 21648, 13530, 511, 63, WACOM_MO },
|
static const struct wacom_features wacom_features_0x14 =
|
||||||
{ "Wacom Bamboo1 Medium", WACOM_PKGLEN_GRAPHIRE, 16704, 12064, 511, 63, GRAPHIRE },
|
{ "Wacom Graphire3 6x8", WACOM_PKGLEN_GRAPHIRE, 16704, 12064, 511, 63, GRAPHIRE };
|
||||||
{ "Wacom Volito", WACOM_PKGLEN_GRAPHIRE, 5104, 3712, 511, 63, GRAPHIRE },
|
static const struct wacom_features wacom_features_0x15 =
|
||||||
{ "Wacom PenStation2", WACOM_PKGLEN_GRAPHIRE, 3250, 2320, 255, 63, GRAPHIRE },
|
{ "Wacom Graphire4 4x5", WACOM_PKGLEN_GRAPHIRE, 10208, 7424, 511, 63, WACOM_G4 };
|
||||||
{ "Wacom Volito2 4x5", WACOM_PKGLEN_GRAPHIRE, 5104, 3712, 511, 63, GRAPHIRE },
|
static const struct wacom_features wacom_features_0x16 =
|
||||||
{ "Wacom Volito2 2x3", WACOM_PKGLEN_GRAPHIRE, 3248, 2320, 511, 63, GRAPHIRE },
|
{ "Wacom Graphire4 6x8", WACOM_PKGLEN_GRAPHIRE, 16704, 12064, 511, 63, WACOM_G4 };
|
||||||
{ "Wacom PenPartner2", WACOM_PKGLEN_GRAPHIRE, 3250, 2320, 511, 63, GRAPHIRE },
|
static const struct wacom_features wacom_features_0x17 =
|
||||||
{ "Wacom Bamboo", WACOM_PKGLEN_BBFUN, 14760, 9225, 511, 63, WACOM_MO },
|
{ "Wacom BambooFun 4x5", WACOM_PKGLEN_BBFUN, 14760, 9225, 511, 63, WACOM_MO };
|
||||||
{ "Wacom Bamboo1", WACOM_PKGLEN_GRAPHIRE, 5104, 3712, 511, 63, GRAPHIRE },
|
static const struct wacom_features wacom_features_0x18 =
|
||||||
{ "Wacom Intuos 4x5", WACOM_PKGLEN_INTUOS, 12700, 10600, 1023, 31, INTUOS },
|
{ "Wacom BambooFun 6x8", WACOM_PKGLEN_BBFUN, 21648, 13530, 511, 63, WACOM_MO };
|
||||||
{ "Wacom Intuos 6x8", WACOM_PKGLEN_INTUOS, 20320, 16240, 1023, 31, INTUOS },
|
static const struct wacom_features wacom_features_0x19 =
|
||||||
{ "Wacom Intuos 9x12", WACOM_PKGLEN_INTUOS, 30480, 24060, 1023, 31, INTUOS },
|
{ "Wacom Bamboo1 Medium", WACOM_PKGLEN_GRAPHIRE, 16704, 12064, 511, 63, GRAPHIRE };
|
||||||
{ "Wacom Intuos 12x12", WACOM_PKGLEN_INTUOS, 30480, 31680, 1023, 31, INTUOS },
|
static const struct wacom_features wacom_features_0x60 =
|
||||||
{ "Wacom Intuos 12x18", WACOM_PKGLEN_INTUOS, 45720, 31680, 1023, 31, INTUOS },
|
{ "Wacom Volito", WACOM_PKGLEN_GRAPHIRE, 5104, 3712, 511, 63, GRAPHIRE };
|
||||||
{ "Wacom PL400", WACOM_PKGLEN_GRAPHIRE, 5408, 4056, 255, 0, PL },
|
static const struct wacom_features wacom_features_0x61 =
|
||||||
{ "Wacom PL500", WACOM_PKGLEN_GRAPHIRE, 6144, 4608, 255, 0, PL },
|
{ "Wacom PenStation2", WACOM_PKGLEN_GRAPHIRE, 3250, 2320, 255, 63, GRAPHIRE };
|
||||||
{ "Wacom PL600", WACOM_PKGLEN_GRAPHIRE, 6126, 4604, 255, 0, PL },
|
static const struct wacom_features wacom_features_0x62 =
|
||||||
{ "Wacom PL600SX", WACOM_PKGLEN_GRAPHIRE, 6260, 5016, 255, 0, PL },
|
{ "Wacom Volito2 4x5", WACOM_PKGLEN_GRAPHIRE, 5104, 3712, 511, 63, GRAPHIRE };
|
||||||
{ "Wacom PL550", WACOM_PKGLEN_GRAPHIRE, 6144, 4608, 511, 0, PL },
|
static const struct wacom_features wacom_features_0x63 =
|
||||||
{ "Wacom PL800", WACOM_PKGLEN_GRAPHIRE, 7220, 5780, 511, 0, PL },
|
{ "Wacom Volito2 2x3", WACOM_PKGLEN_GRAPHIRE, 3248, 2320, 511, 63, GRAPHIRE };
|
||||||
{ "Wacom PL700", WACOM_PKGLEN_GRAPHIRE, 6758, 5406, 511, 0, PL },
|
static const struct wacom_features wacom_features_0x64 =
|
||||||
{ "Wacom PL510", WACOM_PKGLEN_GRAPHIRE, 6282, 4762, 511, 0, PL },
|
{ "Wacom PenPartner2", WACOM_PKGLEN_GRAPHIRE, 3250, 2320, 511, 63, GRAPHIRE };
|
||||||
{ "Wacom DTU710", WACOM_PKGLEN_GRAPHIRE, 34080, 27660, 511, 0, PL },
|
static const struct wacom_features wacom_features_0x65 =
|
||||||
{ "Wacom DTF521", WACOM_PKGLEN_GRAPHIRE, 6282, 4762, 511, 0, PL },
|
{ "Wacom Bamboo", WACOM_PKGLEN_BBFUN, 14760, 9225, 511, 63, WACOM_MO };
|
||||||
{ "Wacom DTF720", WACOM_PKGLEN_GRAPHIRE, 6858, 5506, 511, 0, PL },
|
static const struct wacom_features wacom_features_0x69 =
|
||||||
{ "Wacom DTF720a", WACOM_PKGLEN_GRAPHIRE, 6858, 5506, 511, 0, PL },
|
{ "Wacom Bamboo1", WACOM_PKGLEN_GRAPHIRE, 5104, 3712, 511, 63, GRAPHIRE };
|
||||||
{ "Wacom Cintiq Partner", WACOM_PKGLEN_GRAPHIRE, 20480, 15360, 511, 0, PTU },
|
static const struct wacom_features wacom_features_0x20 =
|
||||||
{ "Wacom Intuos2 4x5", WACOM_PKGLEN_INTUOS, 12700, 10600, 1023, 31, INTUOS },
|
{ "Wacom Intuos 4x5", WACOM_PKGLEN_INTUOS, 12700, 10600, 1023, 31, INTUOS };
|
||||||
{ "Wacom Intuos2 6x8", WACOM_PKGLEN_INTUOS, 20320, 16240, 1023, 31, INTUOS },
|
static const struct wacom_features wacom_features_0x21 =
|
||||||
{ "Wacom Intuos2 9x12", WACOM_PKGLEN_INTUOS, 30480, 24060, 1023, 31, INTUOS },
|
{ "Wacom Intuos 6x8", WACOM_PKGLEN_INTUOS, 20320, 16240, 1023, 31, INTUOS };
|
||||||
{ "Wacom Intuos2 12x12", WACOM_PKGLEN_INTUOS, 30480, 31680, 1023, 31, INTUOS },
|
static const struct wacom_features wacom_features_0x22 =
|
||||||
{ "Wacom Intuos2 12x18", WACOM_PKGLEN_INTUOS, 45720, 31680, 1023, 31, INTUOS },
|
{ "Wacom Intuos 9x12", WACOM_PKGLEN_INTUOS, 30480, 24060, 1023, 31, INTUOS };
|
||||||
{ "Wacom Intuos3 4x5", WACOM_PKGLEN_INTUOS, 25400, 20320, 1023, 63, INTUOS3S },
|
static const struct wacom_features wacom_features_0x23 =
|
||||||
{ "Wacom Intuos3 6x8", WACOM_PKGLEN_INTUOS, 40640, 30480, 1023, 63, INTUOS3 },
|
{ "Wacom Intuos 12x12", WACOM_PKGLEN_INTUOS, 30480, 31680, 1023, 31, INTUOS };
|
||||||
{ "Wacom Intuos3 9x12", WACOM_PKGLEN_INTUOS, 60960, 45720, 1023, 63, INTUOS3 },
|
static const struct wacom_features wacom_features_0x24 =
|
||||||
{ "Wacom Intuos3 12x12", WACOM_PKGLEN_INTUOS, 60960, 60960, 1023, 63, INTUOS3L },
|
{ "Wacom Intuos 12x18", WACOM_PKGLEN_INTUOS, 45720, 31680, 1023, 31, INTUOS };
|
||||||
{ "Wacom Intuos3 12x19", WACOM_PKGLEN_INTUOS, 97536, 60960, 1023, 63, INTUOS3L },
|
static const struct wacom_features wacom_features_0x30 =
|
||||||
{ "Wacom Intuos3 6x11", WACOM_PKGLEN_INTUOS, 54204, 31750, 1023, 63, INTUOS3 },
|
{ "Wacom PL400", WACOM_PKGLEN_GRAPHIRE, 5408, 4056, 255, 0, PL };
|
||||||
{ "Wacom Intuos3 4x6", WACOM_PKGLEN_INTUOS, 31496, 19685, 1023, 63, INTUOS3S },
|
static const struct wacom_features wacom_features_0x31 =
|
||||||
{ "Wacom Intuos4 4x6", WACOM_PKGLEN_INTUOS, 31496, 19685, 2047, 63, INTUOS4S },
|
{ "Wacom PL500", WACOM_PKGLEN_GRAPHIRE, 6144, 4608, 255, 0, PL };
|
||||||
{ "Wacom Intuos4 6x9", WACOM_PKGLEN_INTUOS, 44704, 27940, 2047, 63, INTUOS4 },
|
static const struct wacom_features wacom_features_0x32 =
|
||||||
{ "Wacom Intuos4 8x13", WACOM_PKGLEN_INTUOS, 65024, 40640, 2047, 63, INTUOS4L },
|
{ "Wacom PL600", WACOM_PKGLEN_GRAPHIRE, 6126, 4604, 255, 0, PL };
|
||||||
{ "Wacom Intuos4 12x19", WACOM_PKGLEN_INTUOS, 97536, 60960, 2047, 63, INTUOS4L },
|
static const struct wacom_features wacom_features_0x33 =
|
||||||
{ "Wacom Cintiq 21UX", WACOM_PKGLEN_INTUOS, 87200, 65600, 1023, 63, CINTIQ },
|
{ "Wacom PL600SX", WACOM_PKGLEN_GRAPHIRE, 6260, 5016, 255, 0, PL };
|
||||||
{ "Wacom Cintiq 20WSX", WACOM_PKGLEN_INTUOS, 86680, 54180, 1023, 63, WACOM_BEE },
|
static const struct wacom_features wacom_features_0x34 =
|
||||||
{ "Wacom Cintiq 12WX", WACOM_PKGLEN_INTUOS, 53020, 33440, 1023, 63, WACOM_BEE },
|
{ "Wacom PL550", WACOM_PKGLEN_GRAPHIRE, 6144, 4608, 511, 0, PL };
|
||||||
{ "Wacom DTU1931", WACOM_PKGLEN_GRAPHIRE, 37832, 30305, 511, 0, PL },
|
static const struct wacom_features wacom_features_0x35 =
|
||||||
{ "Wacom ISDv4 90", WACOM_PKGLEN_GRAPHIRE, 26202, 16325, 255, 0, TABLETPC },
|
{ "Wacom PL800", WACOM_PKGLEN_GRAPHIRE, 7220, 5780, 511, 0, PL };
|
||||||
{ "Wacom ISDv4 93", WACOM_PKGLEN_GRAPHIRE, 26202, 16325, 255, 0, TABLETPC },
|
static const struct wacom_features wacom_features_0x37 =
|
||||||
{ "Wacom ISDv4 9A", WACOM_PKGLEN_GRAPHIRE, 26202, 16325, 255, 0, TABLETPC },
|
{ "Wacom PL700", WACOM_PKGLEN_GRAPHIRE, 6758, 5406, 511, 0, PL };
|
||||||
{ "Wacom ISDv4 9F", WACOM_PKGLEN_PENABLED, 26202, 16325, 255, 0, TABLETPC },
|
static const struct wacom_features wacom_features_0x38 =
|
||||||
{ "Wacom ISDv4 E2", WACOM_PKGLEN_TPC2FG, 26202, 16325, 255, 0, TABLETPC2FG },
|
{ "Wacom PL510", WACOM_PKGLEN_GRAPHIRE, 6282, 4762, 511, 0, PL };
|
||||||
{ "Wacom ISDv4 E3", WACOM_PKGLEN_TPC2FG, 26202, 16325, 255, 0, TABLETPC2FG },
|
static const struct wacom_features wacom_features_0x39 =
|
||||||
{ "Wacom Intuos2 6x8", WACOM_PKGLEN_INTUOS, 20320, 16240, 1023, 31, INTUOS },
|
{ "Wacom DTU710", WACOM_PKGLEN_GRAPHIRE, 34080, 27660, 511, 0, PL };
|
||||||
|
static const struct wacom_features wacom_features_0xC4 =
|
||||||
|
{ "Wacom DTF521", WACOM_PKGLEN_GRAPHIRE, 6282, 4762, 511, 0, PL };
|
||||||
|
static const struct wacom_features wacom_features_0xC0 =
|
||||||
|
{ "Wacom DTF720", WACOM_PKGLEN_GRAPHIRE, 6858, 5506, 511, 0, PL };
|
||||||
|
static const struct wacom_features wacom_features_0xC2 =
|
||||||
|
{ "Wacom DTF720a", WACOM_PKGLEN_GRAPHIRE, 6858, 5506, 511, 0, PL };
|
||||||
|
static const struct wacom_features wacom_features_0x03 =
|
||||||
|
{ "Wacom Cintiq Partner", WACOM_PKGLEN_GRAPHIRE, 20480, 15360, 511, 0, PTU };
|
||||||
|
static const struct wacom_features wacom_features_0x41 =
|
||||||
|
{ "Wacom Intuos2 4x5", WACOM_PKGLEN_INTUOS, 12700, 10600, 1023, 31, INTUOS };
|
||||||
|
static const struct wacom_features wacom_features_0x42 =
|
||||||
|
{ "Wacom Intuos2 6x8", WACOM_PKGLEN_INTUOS, 20320, 16240, 1023, 31, INTUOS };
|
||||||
|
static const struct wacom_features wacom_features_0x43 =
|
||||||
|
{ "Wacom Intuos2 9x12", WACOM_PKGLEN_INTUOS, 30480, 24060, 1023, 31, INTUOS };
|
||||||
|
static const struct wacom_features wacom_features_0x44 =
|
||||||
|
{ "Wacom Intuos2 12x12", WACOM_PKGLEN_INTUOS, 30480, 31680, 1023, 31, INTUOS };
|
||||||
|
static const struct wacom_features wacom_features_0x45 =
|
||||||
|
{ "Wacom Intuos2 12x18", WACOM_PKGLEN_INTUOS, 45720, 31680, 1023, 31, INTUOS };
|
||||||
|
static const struct wacom_features wacom_features_0xB0 =
|
||||||
|
{ "Wacom Intuos3 4x5", WACOM_PKGLEN_INTUOS, 25400, 20320, 1023, 63, INTUOS3S };
|
||||||
|
static const struct wacom_features wacom_features_0xB1 =
|
||||||
|
{ "Wacom Intuos3 6x8", WACOM_PKGLEN_INTUOS, 40640, 30480, 1023, 63, INTUOS3 };
|
||||||
|
static const struct wacom_features wacom_features_0xB2 =
|
||||||
|
{ "Wacom Intuos3 9x12", WACOM_PKGLEN_INTUOS, 60960, 45720, 1023, 63, INTUOS3 };
|
||||||
|
static const struct wacom_features wacom_features_0xB3 =
|
||||||
|
{ "Wacom Intuos3 12x12", WACOM_PKGLEN_INTUOS, 60960, 60960, 1023, 63, INTUOS3L };
|
||||||
|
static const struct wacom_features wacom_features_0xB4 =
|
||||||
|
{ "Wacom Intuos3 12x19", WACOM_PKGLEN_INTUOS, 97536, 60960, 1023, 63, INTUOS3L };
|
||||||
|
static const struct wacom_features wacom_features_0xB5 =
|
||||||
|
{ "Wacom Intuos3 6x11", WACOM_PKGLEN_INTUOS, 54204, 31750, 1023, 63, INTUOS3 };
|
||||||
|
static const struct wacom_features wacom_features_0xB7 =
|
||||||
|
{ "Wacom Intuos3 4x6", WACOM_PKGLEN_INTUOS, 31496, 19685, 1023, 63, INTUOS3S };
|
||||||
|
static const struct wacom_features wacom_features_0xB8 =
|
||||||
|
{ "Wacom Intuos4 4x6", WACOM_PKGLEN_INTUOS, 31496, 19685, 2047, 63, INTUOS4S };
|
||||||
|
static const struct wacom_features wacom_features_0xB9 =
|
||||||
|
{ "Wacom Intuos4 6x9", WACOM_PKGLEN_INTUOS, 44704, 27940, 2047, 63, INTUOS4 };
|
||||||
|
static const struct wacom_features wacom_features_0xBA =
|
||||||
|
{ "Wacom Intuos4 8x13", WACOM_PKGLEN_INTUOS, 65024, 40640, 2047, 63, INTUOS4L };
|
||||||
|
static const struct wacom_features wacom_features_0xBB =
|
||||||
|
{ "Wacom Intuos4 12x19", WACOM_PKGLEN_INTUOS, 97536, 60960, 2047, 63, INTUOS4L };
|
||||||
|
static const struct wacom_features wacom_features_0x3F =
|
||||||
|
{ "Wacom Cintiq 21UX", WACOM_PKGLEN_INTUOS, 87200, 65600, 1023, 63, CINTIQ };
|
||||||
|
static const struct wacom_features wacom_features_0xC5 =
|
||||||
|
{ "Wacom Cintiq 20WSX", WACOM_PKGLEN_INTUOS, 86680, 54180, 1023, 63, WACOM_BEE };
|
||||||
|
static const struct wacom_features wacom_features_0xC6 =
|
||||||
|
{ "Wacom Cintiq 12WX", WACOM_PKGLEN_INTUOS, 53020, 33440, 1023, 63, WACOM_BEE };
|
||||||
|
static const struct wacom_features wacom_features_0xC7 =
|
||||||
|
{ "Wacom DTU1931", WACOM_PKGLEN_GRAPHIRE, 37832, 30305, 511, 0, PL };
|
||||||
|
static const struct wacom_features wacom_features_0x90 =
|
||||||
|
{ "Wacom ISDv4 90", WACOM_PKGLEN_GRAPHIRE, 26202, 16325, 255, 0, TABLETPC };
|
||||||
|
static const struct wacom_features wacom_features_0x93 =
|
||||||
|
{ "Wacom ISDv4 93", WACOM_PKGLEN_GRAPHIRE, 26202, 16325, 255, 0, TABLETPC };
|
||||||
|
static const struct wacom_features wacom_features_0x9A =
|
||||||
|
{ "Wacom ISDv4 9A", WACOM_PKGLEN_GRAPHIRE, 26202, 16325, 255, 0, TABLETPC };
|
||||||
|
static const struct wacom_features wacom_features_0x9F =
|
||||||
|
{ "Wacom ISDv4 9F", WACOM_PKGLEN_PENABLED, 26202, 16325, 255, 0, TABLETPC };
|
||||||
|
static const struct wacom_features wacom_features_0xE2 =
|
||||||
|
{ "Wacom ISDv4 E2", WACOM_PKGLEN_TPC2FG, 26202, 16325, 255, 0, TABLETPC2FG };
|
||||||
|
static const struct wacom_features wacom_features_0xE3 =
|
||||||
|
{ "Wacom ISDv4 E3", WACOM_PKGLEN_TPC2FG, 26202, 16325, 255, 0, TABLETPC2FG };
|
||||||
|
static const struct wacom_features wacom_features_0x47 =
|
||||||
|
{ "Wacom Intuos2 6x8", WACOM_PKGLEN_INTUOS, 20320, 16240, 1023, 31, INTUOS };
|
||||||
|
|
||||||
|
#define USB_DEVICE_WACOM(prod) \
|
||||||
|
USB_DEVICE(USB_VENDOR_ID_WACOM, prod), \
|
||||||
|
.driver_info = (kernel_ulong_t)&wacom_features_##prod
|
||||||
|
|
||||||
|
const struct usb_device_id wacom_ids[] = {
|
||||||
|
{ USB_DEVICE_WACOM(0x00) },
|
||||||
|
{ USB_DEVICE_WACOM(0x10) },
|
||||||
|
{ USB_DEVICE_WACOM(0x11) },
|
||||||
|
{ USB_DEVICE_WACOM(0x12) },
|
||||||
|
{ USB_DEVICE_WACOM(0x13) },
|
||||||
|
{ USB_DEVICE_WACOM(0x14) },
|
||||||
|
{ USB_DEVICE_WACOM(0x15) },
|
||||||
|
{ USB_DEVICE_WACOM(0x16) },
|
||||||
|
{ USB_DEVICE_WACOM(0x17) },
|
||||||
|
{ USB_DEVICE_WACOM(0x18) },
|
||||||
|
{ USB_DEVICE_WACOM(0x19) },
|
||||||
|
{ USB_DEVICE_WACOM(0x60) },
|
||||||
|
{ USB_DEVICE_WACOM(0x61) },
|
||||||
|
{ USB_DEVICE_WACOM(0x62) },
|
||||||
|
{ USB_DEVICE_WACOM(0x63) },
|
||||||
|
{ USB_DEVICE_WACOM(0x64) },
|
||||||
|
{ USB_DEVICE_WACOM(0x65) },
|
||||||
|
{ USB_DEVICE_WACOM(0x69) },
|
||||||
|
{ USB_DEVICE_WACOM(0x20) },
|
||||||
|
{ USB_DEVICE_WACOM(0x21) },
|
||||||
|
{ USB_DEVICE_WACOM(0x22) },
|
||||||
|
{ USB_DEVICE_WACOM(0x23) },
|
||||||
|
{ USB_DEVICE_WACOM(0x24) },
|
||||||
|
{ USB_DEVICE_WACOM(0x30) },
|
||||||
|
{ USB_DEVICE_WACOM(0x31) },
|
||||||
|
{ USB_DEVICE_WACOM(0x32) },
|
||||||
|
{ USB_DEVICE_WACOM(0x33) },
|
||||||
|
{ USB_DEVICE_WACOM(0x34) },
|
||||||
|
{ USB_DEVICE_WACOM(0x35) },
|
||||||
|
{ USB_DEVICE_WACOM(0x37) },
|
||||||
|
{ USB_DEVICE_WACOM(0x38) },
|
||||||
|
{ USB_DEVICE_WACOM(0x39) },
|
||||||
|
{ USB_DEVICE_WACOM(0xC4) },
|
||||||
|
{ USB_DEVICE_WACOM(0xC0) },
|
||||||
|
{ USB_DEVICE_WACOM(0xC2) },
|
||||||
|
{ USB_DEVICE_WACOM(0x03) },
|
||||||
|
{ USB_DEVICE_WACOM(0x41) },
|
||||||
|
{ USB_DEVICE_WACOM(0x42) },
|
||||||
|
{ USB_DEVICE_WACOM(0x43) },
|
||||||
|
{ USB_DEVICE_WACOM(0x44) },
|
||||||
|
{ USB_DEVICE_WACOM(0x45) },
|
||||||
|
{ USB_DEVICE_WACOM(0xB0) },
|
||||||
|
{ USB_DEVICE_WACOM(0xB1) },
|
||||||
|
{ USB_DEVICE_WACOM(0xB2) },
|
||||||
|
{ USB_DEVICE_WACOM(0xB3) },
|
||||||
|
{ USB_DEVICE_WACOM(0xB4) },
|
||||||
|
{ USB_DEVICE_WACOM(0xB5) },
|
||||||
|
{ USB_DEVICE_WACOM(0xB7) },
|
||||||
|
{ USB_DEVICE_WACOM(0xB8) },
|
||||||
|
{ USB_DEVICE_WACOM(0xB9) },
|
||||||
|
{ USB_DEVICE_WACOM(0xBA) },
|
||||||
|
{ USB_DEVICE_WACOM(0xBB) },
|
||||||
|
{ USB_DEVICE_WACOM(0x3F) },
|
||||||
|
{ USB_DEVICE_WACOM(0xC5) },
|
||||||
|
{ USB_DEVICE_WACOM(0xC6) },
|
||||||
|
{ USB_DEVICE_WACOM(0xC7) },
|
||||||
|
{ USB_DEVICE_WACOM(0x90) },
|
||||||
|
{ USB_DEVICE_WACOM(0x93) },
|
||||||
|
{ USB_DEVICE_WACOM(0x9A) },
|
||||||
|
{ USB_DEVICE_WACOM(0x9F) },
|
||||||
|
{ USB_DEVICE_WACOM(0xE2) },
|
||||||
|
{ USB_DEVICE_WACOM(0xE3) },
|
||||||
|
{ USB_DEVICE_WACOM(0x47) },
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct usb_device_id wacom_ids[] = {
|
|
||||||
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x00) },
|
|
||||||
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x10) },
|
|
||||||
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x11) },
|
|
||||||
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x12) },
|
|
||||||
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x13) },
|
|
||||||
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x14) },
|
|
||||||
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x15) },
|
|
||||||
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x16) },
|
|
||||||
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x17) },
|
|
||||||
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x18) },
|
|
||||||
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x19) },
|
|
||||||
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x60) },
|
|
||||||
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x61) },
|
|
||||||
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x62) },
|
|
||||||
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x63) },
|
|
||||||
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x64) },
|
|
||||||
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x65) },
|
|
||||||
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x69) },
|
|
||||||
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x20) },
|
|
||||||
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x21) },
|
|
||||||
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x22) },
|
|
||||||
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x23) },
|
|
||||||
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x24) },
|
|
||||||
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x30) },
|
|
||||||
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x31) },
|
|
||||||
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x32) },
|
|
||||||
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x33) },
|
|
||||||
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x34) },
|
|
||||||
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x35) },
|
|
||||||
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x37) },
|
|
||||||
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x38) },
|
|
||||||
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x39) },
|
|
||||||
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0xC4) },
|
|
||||||
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0xC0) },
|
|
||||||
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0xC2) },
|
|
||||||
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x03) },
|
|
||||||
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x41) },
|
|
||||||
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x42) },
|
|
||||||
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x43) },
|
|
||||||
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x44) },
|
|
||||||
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x45) },
|
|
||||||
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB0) },
|
|
||||||
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB1) },
|
|
||||||
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB2) },
|
|
||||||
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB3) },
|
|
||||||
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB4) },
|
|
||||||
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB5) },
|
|
||||||
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB7) },
|
|
||||||
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB8) },
|
|
||||||
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB9) },
|
|
||||||
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0xBA) },
|
|
||||||
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0xBB) },
|
|
||||||
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x3F) },
|
|
||||||
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0xC5) },
|
|
||||||
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0xC6) },
|
|
||||||
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0xC7) },
|
|
||||||
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x90) },
|
|
||||||
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x93) },
|
|
||||||
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x9A) },
|
|
||||||
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x9F) },
|
|
||||||
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0xE2) },
|
|
||||||
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0xE3) },
|
|
||||||
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x47) },
|
|
||||||
{ }
|
|
||||||
};
|
|
||||||
|
|
||||||
const struct usb_device_id *get_device_table(void)
|
|
||||||
{
|
|
||||||
const struct usb_device_id *id_table = wacom_ids;
|
|
||||||
|
|
||||||
return id_table;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct wacom_features * get_wacom_feature(const struct usb_device_id *id)
|
|
||||||
{
|
|
||||||
int index = id - wacom_ids;
|
|
||||||
struct wacom_features *wf = &wacom_features[index];
|
|
||||||
|
|
||||||
return wf;
|
|
||||||
}
|
|
||||||
|
|
||||||
MODULE_DEVICE_TABLE(usb, wacom_ids);
|
MODULE_DEVICE_TABLE(usb, wacom_ids);
|
||||||
|
|
|
||||||
|
|
@ -58,7 +58,7 @@ enum {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct wacom_features {
|
struct wacom_features {
|
||||||
char *name;
|
const char *name;
|
||||||
int pktlen;
|
int pktlen;
|
||||||
int x_max;
|
int x_max;
|
||||||
int y_max;
|
int y_max;
|
||||||
|
|
@ -73,11 +73,12 @@ struct wacom_features {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct wacom_wac {
|
struct wacom_wac {
|
||||||
|
char name[64];
|
||||||
unsigned char *data;
|
unsigned char *data;
|
||||||
int tool[2];
|
int tool[2];
|
||||||
int id[2];
|
int id[2];
|
||||||
__u32 serial[2];
|
__u32 serial[2];
|
||||||
struct wacom_features *features;
|
struct wacom_features features;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -90,7 +90,6 @@ config TOUCHSCREEN_CORGI
|
||||||
tristate "SharpSL (Corgi and Spitz series) touchscreen driver (DEPRECATED)"
|
tristate "SharpSL (Corgi and Spitz series) touchscreen driver (DEPRECATED)"
|
||||||
depends on PXA_SHARPSL
|
depends on PXA_SHARPSL
|
||||||
select CORGI_SSP_DEPRECATED
|
select CORGI_SSP_DEPRECATED
|
||||||
default y
|
|
||||||
help
|
help
|
||||||
Say Y here to enable the driver for the touchscreen on the
|
Say Y here to enable the driver for the touchscreen on the
|
||||||
Sharp SL-C7xx and SL-Cxx00 series of PDAs.
|
Sharp SL-C7xx and SL-Cxx00 series of PDAs.
|
||||||
|
|
@ -537,6 +536,11 @@ config TOUCHSCREEN_USB_ETT_TC5UH
|
||||||
bool "ET&T TC5UH touchscreen controler support" if EMBEDDED
|
bool "ET&T TC5UH touchscreen controler support" if EMBEDDED
|
||||||
depends on TOUCHSCREEN_USB_COMPOSITE
|
depends on TOUCHSCREEN_USB_COMPOSITE
|
||||||
|
|
||||||
|
config TOUCHSCREEN_USB_NEXIO
|
||||||
|
default y
|
||||||
|
bool "NEXIO/iNexio device support" if EMBEDDED
|
||||||
|
depends on TOUCHSCREEN_USB_COMPOSITE
|
||||||
|
|
||||||
config TOUCHSCREEN_TOUCHIT213
|
config TOUCHSCREEN_TOUCHIT213
|
||||||
tristate "Sahara TouchIT-213 touchscreen"
|
tristate "Sahara TouchIT-213 touchscreen"
|
||||||
select SERIO
|
select SERIO
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@
|
||||||
#include <linux/gpio.h>
|
#include <linux/gpio.h>
|
||||||
#include <linux/spi/spi.h>
|
#include <linux/spi/spi.h>
|
||||||
#include <linux/spi/ads7846.h>
|
#include <linux/spi/ads7846.h>
|
||||||
|
#include <linux/regulator/consumer.h>
|
||||||
#include <asm/irq.h>
|
#include <asm/irq.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -85,6 +86,7 @@ struct ads7846 {
|
||||||
char name[32];
|
char name[32];
|
||||||
|
|
||||||
struct spi_device *spi;
|
struct spi_device *spi;
|
||||||
|
struct regulator *reg;
|
||||||
|
|
||||||
#if defined(CONFIG_HWMON) || defined(CONFIG_HWMON_MODULE)
|
#if defined(CONFIG_HWMON) || defined(CONFIG_HWMON_MODULE)
|
||||||
struct attribute_group *attr_group;
|
struct attribute_group *attr_group;
|
||||||
|
|
@ -788,6 +790,8 @@ static void ads7846_disable(struct ads7846 *ts)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
regulator_disable(ts->reg);
|
||||||
|
|
||||||
/* we know the chip's in lowpower mode since we always
|
/* we know the chip's in lowpower mode since we always
|
||||||
* leave it that way after every request
|
* leave it that way after every request
|
||||||
*/
|
*/
|
||||||
|
|
@ -799,6 +803,8 @@ static void ads7846_enable(struct ads7846 *ts)
|
||||||
if (!ts->disabled)
|
if (!ts->disabled)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
regulator_enable(ts->reg);
|
||||||
|
|
||||||
ts->disabled = 0;
|
ts->disabled = 0;
|
||||||
ts->irq_disabled = 0;
|
ts->irq_disabled = 0;
|
||||||
enable_irq(ts->spi->irq);
|
enable_irq(ts->spi->irq);
|
||||||
|
|
@ -1139,6 +1145,19 @@ static int __devinit ads7846_probe(struct spi_device *spi)
|
||||||
|
|
||||||
ts->last_msg = m;
|
ts->last_msg = m;
|
||||||
|
|
||||||
|
ts->reg = regulator_get(&spi->dev, "vcc");
|
||||||
|
if (IS_ERR(ts->reg)) {
|
||||||
|
dev_err(&spi->dev, "unable to get regulator: %ld\n",
|
||||||
|
PTR_ERR(ts->reg));
|
||||||
|
goto err_free_gpio;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = regulator_enable(ts->reg);
|
||||||
|
if (err) {
|
||||||
|
dev_err(&spi->dev, "unable to enable regulator: %d\n", err);
|
||||||
|
goto err_put_regulator;
|
||||||
|
}
|
||||||
|
|
||||||
if (request_irq(spi->irq, ads7846_irq, IRQF_TRIGGER_FALLING,
|
if (request_irq(spi->irq, ads7846_irq, IRQF_TRIGGER_FALLING,
|
||||||
spi->dev.driver->name, ts)) {
|
spi->dev.driver->name, ts)) {
|
||||||
dev_info(&spi->dev,
|
dev_info(&spi->dev,
|
||||||
|
|
@ -1148,7 +1167,7 @@ static int __devinit ads7846_probe(struct spi_device *spi)
|
||||||
spi->dev.driver->name, ts);
|
spi->dev.driver->name, ts);
|
||||||
if (err) {
|
if (err) {
|
||||||
dev_dbg(&spi->dev, "irq %d busy?\n", spi->irq);
|
dev_dbg(&spi->dev, "irq %d busy?\n", spi->irq);
|
||||||
goto err_free_gpio;
|
goto err_disable_regulator;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1180,6 +1199,10 @@ static int __devinit ads7846_probe(struct spi_device *spi)
|
||||||
ads784x_hwmon_unregister(spi, ts);
|
ads784x_hwmon_unregister(spi, ts);
|
||||||
err_free_irq:
|
err_free_irq:
|
||||||
free_irq(spi->irq, ts);
|
free_irq(spi->irq, ts);
|
||||||
|
err_disable_regulator:
|
||||||
|
regulator_disable(ts->reg);
|
||||||
|
err_put_regulator:
|
||||||
|
regulator_put(ts->reg);
|
||||||
err_free_gpio:
|
err_free_gpio:
|
||||||
if (ts->gpio_pendown != -1)
|
if (ts->gpio_pendown != -1)
|
||||||
gpio_free(ts->gpio_pendown);
|
gpio_free(ts->gpio_pendown);
|
||||||
|
|
@ -1208,6 +1231,9 @@ static int __devexit ads7846_remove(struct spi_device *spi)
|
||||||
/* suspend left the IRQ disabled */
|
/* suspend left the IRQ disabled */
|
||||||
enable_irq(ts->spi->irq);
|
enable_irq(ts->spi->irq);
|
||||||
|
|
||||||
|
regulator_disable(ts->reg);
|
||||||
|
regulator_put(ts->reg);
|
||||||
|
|
||||||
if (ts->gpio_pendown != -1)
|
if (ts->gpio_pendown != -1)
|
||||||
gpio_free(ts->gpio_pendown);
|
gpio_free(ts->gpio_pendown);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -72,11 +72,13 @@ static void elo_process_data_10(struct elo *elo, unsigned char data)
|
||||||
struct input_dev *dev = elo->dev;
|
struct input_dev *dev = elo->dev;
|
||||||
|
|
||||||
elo->data[elo->idx] = data;
|
elo->data[elo->idx] = data;
|
||||||
|
|
||||||
switch (elo->idx++) {
|
switch (elo->idx++) {
|
||||||
case 0:
|
case 0:
|
||||||
elo->csum = 0xaa;
|
elo->csum = 0xaa;
|
||||||
if (data != ELO10_LEAD_BYTE) {
|
if (data != ELO10_LEAD_BYTE) {
|
||||||
pr_debug("elo: unsynchronized data: 0x%02x\n", data);
|
dev_dbg(&elo->serio->dev,
|
||||||
|
"unsynchronized data: 0x%02x\n", data);
|
||||||
elo->idx = 0;
|
elo->idx = 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
@ -84,13 +86,15 @@ static void elo_process_data_10(struct elo *elo, unsigned char data)
|
||||||
case 9:
|
case 9:
|
||||||
elo->idx = 0;
|
elo->idx = 0;
|
||||||
if (data != elo->csum) {
|
if (data != elo->csum) {
|
||||||
pr_debug("elo: bad checksum: 0x%02x, expected 0x%02x\n",
|
dev_dbg(&elo->serio->dev,
|
||||||
|
"bad checksum: 0x%02x, expected 0x%02x\n",
|
||||||
data, elo->csum);
|
data, elo->csum);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (elo->data[1] != elo->expected_packet) {
|
if (elo->data[1] != elo->expected_packet) {
|
||||||
if (elo->data[1] != ELO10_TOUCH_PACKET)
|
if (elo->data[1] != ELO10_TOUCH_PACKET)
|
||||||
pr_debug("elo: unexpected packet: 0x%02x\n",
|
dev_dbg(&elo->serio->dev,
|
||||||
|
"unexpected packet: 0x%02x\n",
|
||||||
elo->data[1]);
|
elo->data[1]);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -123,9 +127,20 @@ static void elo_process_data_6(struct elo *elo, unsigned char data)
|
||||||
|
|
||||||
switch (elo->idx++) {
|
switch (elo->idx++) {
|
||||||
|
|
||||||
case 0: if ((data & 0xc0) != 0xc0) elo->idx = 0; break;
|
case 0:
|
||||||
case 1: if ((data & 0xc0) != 0x80) elo->idx = 0; break;
|
if ((data & 0xc0) != 0xc0)
|
||||||
case 2: if ((data & 0xc0) != 0x40) elo->idx = 0; break;
|
elo->idx = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
if ((data & 0xc0) != 0x80)
|
||||||
|
elo->idx = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
if ((data & 0xc0) != 0x40)
|
||||||
|
elo->idx = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
case 3:
|
case 3:
|
||||||
if (data & 0xc0) {
|
if (data & 0xc0) {
|
||||||
|
|
@ -189,7 +204,7 @@ static irqreturn_t elo_interrupt(struct serio *serio,
|
||||||
{
|
{
|
||||||
struct elo *elo = serio_get_drvdata(serio);
|
struct elo *elo = serio_get_drvdata(serio);
|
||||||
|
|
||||||
switch(elo->id) {
|
switch (elo->id) {
|
||||||
case 0:
|
case 0:
|
||||||
elo_process_data_10(elo, data);
|
elo_process_data_10(elo, data);
|
||||||
break;
|
break;
|
||||||
|
|
@ -261,8 +276,8 @@ static int elo_setup_10(struct elo *elo)
|
||||||
if (packet[3] & ELO10_PRESSURE)
|
if (packet[3] & ELO10_PRESSURE)
|
||||||
input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0);
|
input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0);
|
||||||
|
|
||||||
printk(KERN_INFO "elo: %sTouch touchscreen, fw: %02x.%02x, "
|
dev_info(&elo->serio->dev,
|
||||||
"features: 0x%02x, controller: 0x%02x\n",
|
"%sTouch touchscreen, fw: %02x.%02x, features: 0x%02x, controller: 0x%02x\n",
|
||||||
elo_types[(packet[1] -'0') & 0x03],
|
elo_types[(packet[1] -'0') & 0x03],
|
||||||
packet[5], packet[4], packet[3], packet[7]);
|
packet[5], packet[4], packet[3], packet[7]);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -153,6 +153,9 @@ static int wm97xx_acc_pen_down(struct wm97xx *wm)
|
||||||
if (pressure)
|
if (pressure)
|
||||||
p = MODR;
|
p = MODR;
|
||||||
|
|
||||||
|
dev_dbg(wm->dev, "Raw coordinates: x=%x, y=%x, p=%x\n",
|
||||||
|
x, y, p);
|
||||||
|
|
||||||
/* are samples valid */
|
/* are samples valid */
|
||||||
if ((x & WM97XX_ADCSRC_MASK) != WM97XX_ADCSEL_X ||
|
if ((x & WM97XX_ADCSRC_MASK) != WM97XX_ADCSEL_X ||
|
||||||
(y & WM97XX_ADCSRC_MASK) != WM97XX_ADCSEL_Y ||
|
(y & WM97XX_ADCSRC_MASK) != WM97XX_ADCSEL_Y ||
|
||||||
|
|
|
||||||
|
|
@ -128,6 +128,7 @@ static void touch_timer_fire(unsigned long data)
|
||||||
|
|
||||||
down = get_down(data0, data1);
|
down = get_down(data0, data1);
|
||||||
|
|
||||||
|
if (down) {
|
||||||
if (ts.count == (1 << ts.shift)) {
|
if (ts.count == (1 << ts.shift)) {
|
||||||
ts.xp >>= ts.shift;
|
ts.xp >>= ts.shift;
|
||||||
ts.yp >>= ts.shift;
|
ts.yp >>= ts.shift;
|
||||||
|
|
@ -146,9 +147,10 @@ static void touch_timer_fire(unsigned long data)
|
||||||
ts.count = 0;
|
ts.count = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (down) {
|
|
||||||
s3c_adc_start(ts.client, 0, 1 << ts.shift);
|
s3c_adc_start(ts.client, 0, 1 << ts.shift);
|
||||||
} else {
|
} else {
|
||||||
|
ts.xp = 0;
|
||||||
|
ts.yp = 0;
|
||||||
ts.count = 0;
|
ts.count = 0;
|
||||||
|
|
||||||
input_report_key(ts.input, BTN_TOUCH, 0);
|
input_report_key(ts.input, BTN_TOUCH, 0);
|
||||||
|
|
@ -401,6 +403,7 @@ static int s3c2410ts_resume(struct device *dev)
|
||||||
struct s3c2410_ts_mach_info *info = pdev->dev.platform_data;
|
struct s3c2410_ts_mach_info *info = pdev->dev.platform_data;
|
||||||
|
|
||||||
clk_enable(ts.clock);
|
clk_enable(ts.clock);
|
||||||
|
enable_irq(ts.irq_tc);
|
||||||
|
|
||||||
/* Initialise registers */
|
/* Initialise registers */
|
||||||
if ((info->delay & 0xffff) > 0)
|
if ((info->delay & 0xffff) > 0)
|
||||||
|
|
|
||||||
|
|
@ -358,7 +358,7 @@ static int __devexit tsc2007_remove(struct i2c_client *client)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct i2c_device_id tsc2007_idtable[] = {
|
static const struct i2c_device_id tsc2007_idtable[] = {
|
||||||
{ "tsc2007", 0 },
|
{ "tsc2007", 0 },
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@
|
||||||
* - GoTop Super_Q2/GogoPen/PenPower tablets
|
* - GoTop Super_Q2/GogoPen/PenPower tablets
|
||||||
* - JASTEC USB touch controller/DigiTech DTR-02U
|
* - JASTEC USB touch controller/DigiTech DTR-02U
|
||||||
* - Zytronic capacitive touchscreen
|
* - Zytronic capacitive touchscreen
|
||||||
|
* - NEXIO/iNexio
|
||||||
*
|
*
|
||||||
* Copyright (C) 2004-2007 by Daniel Ritz <daniel.ritz@gmx.ch>
|
* Copyright (C) 2004-2007 by Daniel Ritz <daniel.ritz@gmx.ch>
|
||||||
* Copyright (C) by Todd E. Johnson (mtouchusb.c)
|
* Copyright (C) by Todd E. Johnson (mtouchusb.c)
|
||||||
|
|
@ -95,6 +96,7 @@ struct usbtouch_device_info {
|
||||||
|
|
||||||
int (*read_data) (struct usbtouch_usb *usbtouch, unsigned char *pkt);
|
int (*read_data) (struct usbtouch_usb *usbtouch, unsigned char *pkt);
|
||||||
int (*init) (struct usbtouch_usb *usbtouch);
|
int (*init) (struct usbtouch_usb *usbtouch);
|
||||||
|
void (*exit) (struct usbtouch_usb *usbtouch);
|
||||||
};
|
};
|
||||||
|
|
||||||
/* a usbtouch device */
|
/* a usbtouch device */
|
||||||
|
|
@ -104,11 +106,12 @@ struct usbtouch_usb {
|
||||||
unsigned char *buffer;
|
unsigned char *buffer;
|
||||||
int buf_len;
|
int buf_len;
|
||||||
struct urb *irq;
|
struct urb *irq;
|
||||||
struct usb_device *udev;
|
struct usb_interface *interface;
|
||||||
struct input_dev *input;
|
struct input_dev *input;
|
||||||
struct usbtouch_device_info *type;
|
struct usbtouch_device_info *type;
|
||||||
char name[128];
|
char name[128];
|
||||||
char phys[64];
|
char phys[64];
|
||||||
|
void *priv;
|
||||||
|
|
||||||
int x, y;
|
int x, y;
|
||||||
int touch, press;
|
int touch, press;
|
||||||
|
|
@ -133,6 +136,7 @@ enum {
|
||||||
DEVTYPE_E2I,
|
DEVTYPE_E2I,
|
||||||
DEVTYPE_ZYTRONIC,
|
DEVTYPE_ZYTRONIC,
|
||||||
DEVTYPE_TC5UH,
|
DEVTYPE_TC5UH,
|
||||||
|
DEVTYPE_NEXIO,
|
||||||
};
|
};
|
||||||
|
|
||||||
#define USB_DEVICE_HID_CLASS(vend, prod) \
|
#define USB_DEVICE_HID_CLASS(vend, prod) \
|
||||||
|
|
@ -144,7 +148,7 @@ enum {
|
||||||
.bInterfaceClass = USB_INTERFACE_CLASS_HID, \
|
.bInterfaceClass = USB_INTERFACE_CLASS_HID, \
|
||||||
.bInterfaceProtocol = USB_INTERFACE_PROTOCOL_MOUSE
|
.bInterfaceProtocol = USB_INTERFACE_PROTOCOL_MOUSE
|
||||||
|
|
||||||
static struct usb_device_id usbtouch_devices[] = {
|
static const struct usb_device_id usbtouch_devices[] = {
|
||||||
#ifdef CONFIG_TOUCHSCREEN_USB_EGALAX
|
#ifdef CONFIG_TOUCHSCREEN_USB_EGALAX
|
||||||
/* ignore the HID capable devices, handled by usbhid */
|
/* ignore the HID capable devices, handled by usbhid */
|
||||||
{USB_DEVICE_HID_CLASS(0x0eef, 0x0001), .driver_info = DEVTYPE_IGNORE},
|
{USB_DEVICE_HID_CLASS(0x0eef, 0x0001), .driver_info = DEVTYPE_IGNORE},
|
||||||
|
|
@ -222,6 +226,14 @@ static struct usb_device_id usbtouch_devices[] = {
|
||||||
{USB_DEVICE(0x0664, 0x0309), .driver_info = DEVTYPE_TC5UH},
|
{USB_DEVICE(0x0664, 0x0309), .driver_info = DEVTYPE_TC5UH},
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_TOUCHSCREEN_USB_NEXIO
|
||||||
|
/* data interface only */
|
||||||
|
{USB_DEVICE_AND_INTERFACE_INFO(0x10f0, 0x2002, 0x0a, 0x00, 0x00),
|
||||||
|
.driver_info = DEVTYPE_NEXIO},
|
||||||
|
{USB_DEVICE_AND_INTERFACE_INFO(0x1870, 0x0001, 0x0a, 0x00, 0x00),
|
||||||
|
.driver_info = DEVTYPE_NEXIO},
|
||||||
|
#endif
|
||||||
|
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -234,8 +246,9 @@ static struct usb_device_id usbtouch_devices[] = {
|
||||||
static int e2i_init(struct usbtouch_usb *usbtouch)
|
static int e2i_init(struct usbtouch_usb *usbtouch)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
struct usb_device *udev = interface_to_usbdev(usbtouch->interface);
|
||||||
|
|
||||||
ret = usb_control_msg(usbtouch->udev, usb_rcvctrlpipe(usbtouch->udev, 0),
|
ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
|
||||||
0x01, 0x02, 0x0000, 0x0081,
|
0x01, 0x02, 0x0000, 0x0081,
|
||||||
NULL, 0, USB_CTRL_SET_TIMEOUT);
|
NULL, 0, USB_CTRL_SET_TIMEOUT);
|
||||||
|
|
||||||
|
|
@ -344,8 +357,9 @@ static int mtouch_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
|
||||||
static int mtouch_init(struct usbtouch_usb *usbtouch)
|
static int mtouch_init(struct usbtouch_usb *usbtouch)
|
||||||
{
|
{
|
||||||
int ret, i;
|
int ret, i;
|
||||||
|
struct usb_device *udev = interface_to_usbdev(usbtouch->interface);
|
||||||
|
|
||||||
ret = usb_control_msg(usbtouch->udev, usb_rcvctrlpipe(usbtouch->udev, 0),
|
ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
|
||||||
MTOUCHUSB_RESET,
|
MTOUCHUSB_RESET,
|
||||||
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
|
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
|
||||||
1, 0, NULL, 0, USB_CTRL_SET_TIMEOUT);
|
1, 0, NULL, 0, USB_CTRL_SET_TIMEOUT);
|
||||||
|
|
@ -356,7 +370,7 @@ static int mtouch_init(struct usbtouch_usb *usbtouch)
|
||||||
msleep(150);
|
msleep(150);
|
||||||
|
|
||||||
for (i = 0; i < 3; i++) {
|
for (i = 0; i < 3; i++) {
|
||||||
ret = usb_control_msg(usbtouch->udev, usb_rcvctrlpipe(usbtouch->udev, 0),
|
ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
|
||||||
MTOUCHUSB_ASYNC_REPORT,
|
MTOUCHUSB_ASYNC_REPORT,
|
||||||
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
|
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
|
||||||
1, 1, NULL, 0, USB_CTRL_SET_TIMEOUT);
|
1, 1, NULL, 0, USB_CTRL_SET_TIMEOUT);
|
||||||
|
|
@ -489,7 +503,7 @@ static int gunze_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
|
||||||
|
|
||||||
static int dmc_tsc10_init(struct usbtouch_usb *usbtouch)
|
static int dmc_tsc10_init(struct usbtouch_usb *usbtouch)
|
||||||
{
|
{
|
||||||
struct usb_device *dev = usbtouch->udev;
|
struct usb_device *dev = interface_to_usbdev(usbtouch->interface);
|
||||||
int ret = -ENOMEM;
|
int ret = -ENOMEM;
|
||||||
unsigned char *buf;
|
unsigned char *buf;
|
||||||
|
|
||||||
|
|
@ -689,6 +703,229 @@ static int zytronic_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* NEXIO Part
|
||||||
|
*/
|
||||||
|
#ifdef CONFIG_TOUCHSCREEN_USB_NEXIO
|
||||||
|
|
||||||
|
#define NEXIO_TIMEOUT 5000
|
||||||
|
#define NEXIO_BUFSIZE 1024
|
||||||
|
#define NEXIO_THRESHOLD 50
|
||||||
|
|
||||||
|
struct nexio_priv {
|
||||||
|
struct urb *ack;
|
||||||
|
unsigned char *ack_buf;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct nexio_touch_packet {
|
||||||
|
u8 flags; /* 0xe1 = touch, 0xe1 = release */
|
||||||
|
__be16 data_len; /* total bytes of touch data */
|
||||||
|
__be16 x_len; /* bytes for X axis */
|
||||||
|
__be16 y_len; /* bytes for Y axis */
|
||||||
|
u8 data[];
|
||||||
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
static unsigned char nexio_ack_pkt[2] = { 0xaa, 0x02 };
|
||||||
|
static unsigned char nexio_init_pkt[4] = { 0x82, 0x04, 0x0a, 0x0f };
|
||||||
|
|
||||||
|
static void nexio_ack_complete(struct urb *urb)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static int nexio_init(struct usbtouch_usb *usbtouch)
|
||||||
|
{
|
||||||
|
struct usb_device *dev = interface_to_usbdev(usbtouch->interface);
|
||||||
|
struct usb_host_interface *interface = usbtouch->interface->cur_altsetting;
|
||||||
|
struct nexio_priv *priv;
|
||||||
|
int ret = -ENOMEM;
|
||||||
|
int actual_len, i;
|
||||||
|
unsigned char *buf;
|
||||||
|
char *firmware_ver = NULL, *device_name = NULL;
|
||||||
|
int input_ep = 0, output_ep = 0;
|
||||||
|
|
||||||
|
/* find first input and output endpoint */
|
||||||
|
for (i = 0; i < interface->desc.bNumEndpoints; i++) {
|
||||||
|
if (!input_ep &&
|
||||||
|
usb_endpoint_dir_in(&interface->endpoint[i].desc))
|
||||||
|
input_ep = interface->endpoint[i].desc.bEndpointAddress;
|
||||||
|
if (!output_ep &&
|
||||||
|
usb_endpoint_dir_out(&interface->endpoint[i].desc))
|
||||||
|
output_ep = interface->endpoint[i].desc.bEndpointAddress;
|
||||||
|
}
|
||||||
|
if (!input_ep || !output_ep)
|
||||||
|
return -ENXIO;
|
||||||
|
|
||||||
|
buf = kmalloc(NEXIO_BUFSIZE, GFP_KERNEL);
|
||||||
|
if (!buf)
|
||||||
|
goto out_buf;
|
||||||
|
|
||||||
|
/* two empty reads */
|
||||||
|
for (i = 0; i < 2; i++) {
|
||||||
|
ret = usb_bulk_msg(dev, usb_rcvbulkpipe(dev, input_ep),
|
||||||
|
buf, NEXIO_BUFSIZE, &actual_len,
|
||||||
|
NEXIO_TIMEOUT);
|
||||||
|
if (ret < 0)
|
||||||
|
goto out_buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* send init command */
|
||||||
|
memcpy(buf, nexio_init_pkt, sizeof(nexio_init_pkt));
|
||||||
|
ret = usb_bulk_msg(dev, usb_sndbulkpipe(dev, output_ep),
|
||||||
|
buf, sizeof(nexio_init_pkt), &actual_len,
|
||||||
|
NEXIO_TIMEOUT);
|
||||||
|
if (ret < 0)
|
||||||
|
goto out_buf;
|
||||||
|
|
||||||
|
/* read replies */
|
||||||
|
for (i = 0; i < 3; i++) {
|
||||||
|
memset(buf, 0, NEXIO_BUFSIZE);
|
||||||
|
ret = usb_bulk_msg(dev, usb_rcvbulkpipe(dev, input_ep),
|
||||||
|
buf, NEXIO_BUFSIZE, &actual_len,
|
||||||
|
NEXIO_TIMEOUT);
|
||||||
|
if (ret < 0 || actual_len < 1 || buf[1] != actual_len)
|
||||||
|
continue;
|
||||||
|
switch (buf[0]) {
|
||||||
|
case 0x83: /* firmware version */
|
||||||
|
if (!firmware_ver)
|
||||||
|
firmware_ver = kstrdup(&buf[2], GFP_KERNEL);
|
||||||
|
break;
|
||||||
|
case 0x84: /* device name */
|
||||||
|
if (!device_name)
|
||||||
|
device_name = kstrdup(&buf[2], GFP_KERNEL);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
printk(KERN_INFO "Nexio device: %s, firmware version: %s\n",
|
||||||
|
device_name, firmware_ver);
|
||||||
|
|
||||||
|
kfree(firmware_ver);
|
||||||
|
kfree(device_name);
|
||||||
|
|
||||||
|
/* prepare ACK URB */
|
||||||
|
ret = -ENOMEM;
|
||||||
|
|
||||||
|
usbtouch->priv = kmalloc(sizeof(struct nexio_priv), GFP_KERNEL);
|
||||||
|
if (!usbtouch->priv)
|
||||||
|
goto out_buf;
|
||||||
|
|
||||||
|
priv = usbtouch->priv;
|
||||||
|
|
||||||
|
priv->ack_buf = kmalloc(sizeof(nexio_ack_pkt), GFP_KERNEL);
|
||||||
|
if (!priv->ack_buf)
|
||||||
|
goto err_priv;
|
||||||
|
|
||||||
|
memcpy(priv->ack_buf, nexio_ack_pkt, sizeof(nexio_ack_pkt));
|
||||||
|
|
||||||
|
priv->ack = usb_alloc_urb(0, GFP_KERNEL);
|
||||||
|
if (!priv->ack) {
|
||||||
|
dbg("%s - usb_alloc_urb failed: usbtouch->ack", __func__);
|
||||||
|
goto err_ack_buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
usb_fill_bulk_urb(priv->ack, dev, usb_sndbulkpipe(dev, output_ep),
|
||||||
|
priv->ack_buf, sizeof(nexio_ack_pkt),
|
||||||
|
nexio_ack_complete, usbtouch);
|
||||||
|
ret = 0;
|
||||||
|
goto out_buf;
|
||||||
|
|
||||||
|
err_ack_buf:
|
||||||
|
kfree(priv->ack_buf);
|
||||||
|
err_priv:
|
||||||
|
kfree(priv);
|
||||||
|
out_buf:
|
||||||
|
kfree(buf);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void nexio_exit(struct usbtouch_usb *usbtouch)
|
||||||
|
{
|
||||||
|
struct nexio_priv *priv = usbtouch->priv;
|
||||||
|
|
||||||
|
usb_kill_urb(priv->ack);
|
||||||
|
usb_free_urb(priv->ack);
|
||||||
|
kfree(priv->ack_buf);
|
||||||
|
kfree(priv);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int nexio_read_data(struct usbtouch_usb *usbtouch, unsigned char *pkt)
|
||||||
|
{
|
||||||
|
int x, y, begin_x, begin_y, end_x, end_y, w, h, ret;
|
||||||
|
struct nexio_touch_packet *packet = (void *) pkt;
|
||||||
|
struct nexio_priv *priv = usbtouch->priv;
|
||||||
|
|
||||||
|
/* got touch data? */
|
||||||
|
if ((pkt[0] & 0xe0) != 0xe0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* send ACK */
|
||||||
|
ret = usb_submit_urb(priv->ack, GFP_ATOMIC);
|
||||||
|
|
||||||
|
if (!usbtouch->type->max_xc) {
|
||||||
|
usbtouch->type->max_xc = 2 * be16_to_cpu(packet->x_len);
|
||||||
|
input_set_abs_params(usbtouch->input, ABS_X, 0,
|
||||||
|
2 * be16_to_cpu(packet->x_len), 0, 0);
|
||||||
|
usbtouch->type->max_yc = 2 * be16_to_cpu(packet->y_len);
|
||||||
|
input_set_abs_params(usbtouch->input, ABS_Y, 0,
|
||||||
|
2 * be16_to_cpu(packet->y_len), 0, 0);
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* The device reports state of IR sensors on X and Y axes.
|
||||||
|
* Each byte represents "darkness" percentage (0-100) of one element.
|
||||||
|
* 17" touchscreen reports only 64 x 52 bytes so the resolution is low.
|
||||||
|
* This also means that there's a limited multi-touch capability but
|
||||||
|
* it's disabled (and untested) here as there's no X driver for that.
|
||||||
|
*/
|
||||||
|
begin_x = end_x = begin_y = end_y = -1;
|
||||||
|
for (x = 0; x < be16_to_cpu(packet->x_len); x++) {
|
||||||
|
if (begin_x == -1 && packet->data[x] > NEXIO_THRESHOLD) {
|
||||||
|
begin_x = x;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (end_x == -1 && begin_x != -1 && packet->data[x] < NEXIO_THRESHOLD) {
|
||||||
|
end_x = x - 1;
|
||||||
|
for (y = be16_to_cpu(packet->x_len);
|
||||||
|
y < be16_to_cpu(packet->data_len); y++) {
|
||||||
|
if (begin_y == -1 && packet->data[y] > NEXIO_THRESHOLD) {
|
||||||
|
begin_y = y - be16_to_cpu(packet->x_len);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (end_y == -1 &&
|
||||||
|
begin_y != -1 && packet->data[y] < NEXIO_THRESHOLD) {
|
||||||
|
end_y = y - 1 - be16_to_cpu(packet->x_len);
|
||||||
|
w = end_x - begin_x;
|
||||||
|
h = end_y - begin_y;
|
||||||
|
#if 0
|
||||||
|
/* multi-touch */
|
||||||
|
input_report_abs(usbtouch->input,
|
||||||
|
ABS_MT_TOUCH_MAJOR, max(w,h));
|
||||||
|
input_report_abs(usbtouch->input,
|
||||||
|
ABS_MT_TOUCH_MINOR, min(x,h));
|
||||||
|
input_report_abs(usbtouch->input,
|
||||||
|
ABS_MT_POSITION_X, 2*begin_x+w);
|
||||||
|
input_report_abs(usbtouch->input,
|
||||||
|
ABS_MT_POSITION_Y, 2*begin_y+h);
|
||||||
|
input_report_abs(usbtouch->input,
|
||||||
|
ABS_MT_ORIENTATION, w > h);
|
||||||
|
input_mt_sync(usbtouch->input);
|
||||||
|
#endif
|
||||||
|
/* single touch */
|
||||||
|
usbtouch->x = 2 * begin_x + w;
|
||||||
|
usbtouch->y = 2 * begin_y + h;
|
||||||
|
usbtouch->touch = packet->flags & 0x01;
|
||||||
|
begin_y = end_y = -1;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
begin_x = end_x = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
* the different device descriptors
|
* the different device descriptors
|
||||||
*/
|
*/
|
||||||
|
|
@ -873,6 +1110,16 @@ static struct usbtouch_device_info usbtouch_dev_info[] = {
|
||||||
.read_data = tc5uh_read_data,
|
.read_data = tc5uh_read_data,
|
||||||
},
|
},
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_TOUCHSCREEN_USB_NEXIO
|
||||||
|
[DEVTYPE_NEXIO] = {
|
||||||
|
.rept_size = 128,
|
||||||
|
.irq_always = true,
|
||||||
|
.read_data = nexio_read_data,
|
||||||
|
.init = nexio_init,
|
||||||
|
.exit = nexio_exit,
|
||||||
|
},
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -998,6 +1245,7 @@ static void usbtouch_irq(struct urb *urb)
|
||||||
case -ECONNRESET:
|
case -ECONNRESET:
|
||||||
case -ENOENT:
|
case -ENOENT:
|
||||||
case -ESHUTDOWN:
|
case -ESHUTDOWN:
|
||||||
|
case -EPIPE:
|
||||||
/* this urb is terminated, clean up */
|
/* this urb is terminated, clean up */
|
||||||
dbg("%s - urb shutting down with status: %d",
|
dbg("%s - urb shutting down with status: %d",
|
||||||
__func__, urb->status);
|
__func__, urb->status);
|
||||||
|
|
@ -1021,7 +1269,7 @@ static int usbtouch_open(struct input_dev *input)
|
||||||
{
|
{
|
||||||
struct usbtouch_usb *usbtouch = input_get_drvdata(input);
|
struct usbtouch_usb *usbtouch = input_get_drvdata(input);
|
||||||
|
|
||||||
usbtouch->irq->dev = usbtouch->udev;
|
usbtouch->irq->dev = interface_to_usbdev(usbtouch->interface);
|
||||||
|
|
||||||
if (!usbtouch->type->irq_always) {
|
if (!usbtouch->type->irq_always) {
|
||||||
if (usb_submit_urb(usbtouch->irq, GFP_KERNEL))
|
if (usb_submit_urb(usbtouch->irq, GFP_KERNEL))
|
||||||
|
|
@ -1048,13 +1296,23 @@ static void usbtouch_free_buffers(struct usb_device *udev,
|
||||||
kfree(usbtouch->buffer);
|
kfree(usbtouch->buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct usb_endpoint_descriptor *
|
||||||
|
usbtouch_get_input_endpoint(struct usb_host_interface *interface)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < interface->desc.bNumEndpoints; i++)
|
||||||
|
if (usb_endpoint_dir_in(&interface->endpoint[i].desc))
|
||||||
|
return &interface->endpoint[i].desc;
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static int usbtouch_probe(struct usb_interface *intf,
|
static int usbtouch_probe(struct usb_interface *intf,
|
||||||
const struct usb_device_id *id)
|
const struct usb_device_id *id)
|
||||||
{
|
{
|
||||||
struct usbtouch_usb *usbtouch;
|
struct usbtouch_usb *usbtouch;
|
||||||
struct input_dev *input_dev;
|
struct input_dev *input_dev;
|
||||||
struct usb_host_interface *interface;
|
|
||||||
struct usb_endpoint_descriptor *endpoint;
|
struct usb_endpoint_descriptor *endpoint;
|
||||||
struct usb_device *udev = interface_to_usbdev(intf);
|
struct usb_device *udev = interface_to_usbdev(intf);
|
||||||
struct usbtouch_device_info *type;
|
struct usbtouch_device_info *type;
|
||||||
|
|
@ -1064,8 +1322,9 @@ static int usbtouch_probe(struct usb_interface *intf,
|
||||||
if (id->driver_info == DEVTYPE_IGNORE)
|
if (id->driver_info == DEVTYPE_IGNORE)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
interface = intf->cur_altsetting;
|
endpoint = usbtouch_get_input_endpoint(intf->cur_altsetting);
|
||||||
endpoint = &interface->endpoint[0].desc;
|
if (!endpoint)
|
||||||
|
return -ENXIO;
|
||||||
|
|
||||||
usbtouch = kzalloc(sizeof(struct usbtouch_usb), GFP_KERNEL);
|
usbtouch = kzalloc(sizeof(struct usbtouch_usb), GFP_KERNEL);
|
||||||
input_dev = input_allocate_device();
|
input_dev = input_allocate_device();
|
||||||
|
|
@ -1094,7 +1353,7 @@ static int usbtouch_probe(struct usb_interface *intf,
|
||||||
goto out_free_buffers;
|
goto out_free_buffers;
|
||||||
}
|
}
|
||||||
|
|
||||||
usbtouch->udev = udev;
|
usbtouch->interface = intf;
|
||||||
usbtouch->input = input_dev;
|
usbtouch->input = input_dev;
|
||||||
|
|
||||||
if (udev->manufacturer)
|
if (udev->manufacturer)
|
||||||
|
|
@ -1133,12 +1392,18 @@ static int usbtouch_probe(struct usb_interface *intf,
|
||||||
input_set_abs_params(input_dev, ABS_PRESSURE, type->min_press,
|
input_set_abs_params(input_dev, ABS_PRESSURE, type->min_press,
|
||||||
type->max_press, 0, 0);
|
type->max_press, 0, 0);
|
||||||
|
|
||||||
usb_fill_int_urb(usbtouch->irq, usbtouch->udev,
|
if (usb_endpoint_type(endpoint) == USB_ENDPOINT_XFER_INT)
|
||||||
usb_rcvintpipe(usbtouch->udev, endpoint->bEndpointAddress),
|
usb_fill_int_urb(usbtouch->irq, udev,
|
||||||
|
usb_rcvintpipe(udev, endpoint->bEndpointAddress),
|
||||||
usbtouch->data, type->rept_size,
|
usbtouch->data, type->rept_size,
|
||||||
usbtouch_irq, usbtouch, endpoint->bInterval);
|
usbtouch_irq, usbtouch, endpoint->bInterval);
|
||||||
|
else
|
||||||
|
usb_fill_bulk_urb(usbtouch->irq, udev,
|
||||||
|
usb_rcvbulkpipe(udev, endpoint->bEndpointAddress),
|
||||||
|
usbtouch->data, type->rept_size,
|
||||||
|
usbtouch_irq, usbtouch);
|
||||||
|
|
||||||
usbtouch->irq->dev = usbtouch->udev;
|
usbtouch->irq->dev = udev;
|
||||||
usbtouch->irq->transfer_dma = usbtouch->data_dma;
|
usbtouch->irq->transfer_dma = usbtouch->data_dma;
|
||||||
usbtouch->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
|
usbtouch->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
|
||||||
|
|
||||||
|
|
@ -1147,23 +1412,37 @@ static int usbtouch_probe(struct usb_interface *intf,
|
||||||
err = type->init(usbtouch);
|
err = type->init(usbtouch);
|
||||||
if (err) {
|
if (err) {
|
||||||
dbg("%s - type->init() failed, err: %d", __func__, err);
|
dbg("%s - type->init() failed, err: %d", __func__, err);
|
||||||
goto out_free_buffers;
|
goto out_free_urb;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err = input_register_device(usbtouch->input);
|
err = input_register_device(usbtouch->input);
|
||||||
if (err) {
|
if (err) {
|
||||||
dbg("%s - input_register_device failed, err: %d", __func__, err);
|
dbg("%s - input_register_device failed, err: %d", __func__, err);
|
||||||
goto out_free_buffers;
|
goto out_do_exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
usb_set_intfdata(intf, usbtouch);
|
usb_set_intfdata(intf, usbtouch);
|
||||||
|
|
||||||
if (usbtouch->type->irq_always)
|
if (usbtouch->type->irq_always) {
|
||||||
usb_submit_urb(usbtouch->irq, GFP_KERNEL);
|
err = usb_submit_urb(usbtouch->irq, GFP_KERNEL);
|
||||||
|
if (err) {
|
||||||
|
err("%s - usb_submit_urb failed with result: %d",
|
||||||
|
__func__, err);
|
||||||
|
goto out_unregister_input;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
out_unregister_input:
|
||||||
|
input_unregister_device(input_dev);
|
||||||
|
input_dev = NULL;
|
||||||
|
out_do_exit:
|
||||||
|
if (type->exit)
|
||||||
|
type->exit(usbtouch);
|
||||||
|
out_free_urb:
|
||||||
|
usb_free_urb(usbtouch->irq);
|
||||||
out_free_buffers:
|
out_free_buffers:
|
||||||
usbtouch_free_buffers(udev, usbtouch);
|
usbtouch_free_buffers(udev, usbtouch);
|
||||||
out_free:
|
out_free:
|
||||||
|
|
@ -1186,6 +1465,8 @@ static void usbtouch_disconnect(struct usb_interface *intf)
|
||||||
/* this will stop IO via close */
|
/* this will stop IO via close */
|
||||||
input_unregister_device(usbtouch->input);
|
input_unregister_device(usbtouch->input);
|
||||||
usb_free_urb(usbtouch->irq);
|
usb_free_urb(usbtouch->irq);
|
||||||
|
if (usbtouch->type->exit)
|
||||||
|
usbtouch->type->exit(usbtouch);
|
||||||
usbtouch_free_buffers(interface_to_usbdev(intf), usbtouch);
|
usbtouch_free_buffers(interface_to_usbdev(intf), usbtouch);
|
||||||
kfree(usbtouch);
|
kfree(usbtouch);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -118,6 +118,9 @@ static int wm97xx_acc_pen_down(struct wm97xx *wm)
|
||||||
if (pressure)
|
if (pressure)
|
||||||
p = MODR;
|
p = MODR;
|
||||||
|
|
||||||
|
dev_dbg(wm->dev, "Raw coordinates: x=%x, y=%x, p=%x\n",
|
||||||
|
x, y, p);
|
||||||
|
|
||||||
/* are samples valid */
|
/* are samples valid */
|
||||||
if ((x & WM97XX_ADCSRC_MASK) != WM97XX_ADCSEL_X ||
|
if ((x & WM97XX_ADCSRC_MASK) != WM97XX_ADCSEL_X ||
|
||||||
(y & WM97XX_ADCSRC_MASK) != WM97XX_ADCSEL_Y ||
|
(y & WM97XX_ADCSRC_MASK) != WM97XX_ADCSEL_Y ||
|
||||||
|
|
|
||||||
|
|
@ -321,7 +321,7 @@ InitWait:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct xenbus_device_id xenkbd_ids[] = {
|
static const struct xenbus_device_id xenkbd_ids[] = {
|
||||||
{ "vkbd" },
|
{ "vkbd" },
|
||||||
{ "" }
|
{ "" }
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -171,8 +171,8 @@ config INPUT_ADBHID
|
||||||
If unsure, say Y.
|
If unsure, say Y.
|
||||||
|
|
||||||
config MAC_EMUMOUSEBTN
|
config MAC_EMUMOUSEBTN
|
||||||
bool "Support for mouse button 2+3 emulation"
|
tristate "Support for mouse button 2+3 emulation"
|
||||||
select INPUT
|
depends on SYSCTL && INPUT
|
||||||
help
|
help
|
||||||
This provides generic support for emulating the 2nd and 3rd mouse
|
This provides generic support for emulating the 2nd and 3rd mouse
|
||||||
button with keypresses. If you say Y here, the emulation is still
|
button with keypresses. If you say Y here, the emulation is still
|
||||||
|
|
@ -184,6 +184,9 @@ config MAC_EMUMOUSEBTN
|
||||||
|
|
||||||
If you have an Apple machine with a 1-button mouse, say Y here.
|
If you have an Apple machine with a 1-button mouse, say Y here.
|
||||||
|
|
||||||
|
To compile this driver as a module, choose M here: the
|
||||||
|
module will be called mac_hid.
|
||||||
|
|
||||||
config THERM_WINDTUNNEL
|
config THERM_WINDTUNNEL
|
||||||
tristate "Support for thermal management on Windtunnel G4s"
|
tristate "Support for thermal management on Windtunnel G4s"
|
||||||
depends on I2C && I2C_POWERMAC && PPC_PMAC && !PPC_PMAC64
|
depends on I2C && I2C_POWERMAC && PPC_PMAC && !PPC_PMAC64
|
||||||
|
|
|
||||||
|
|
@ -13,17 +13,197 @@
|
||||||
#include <linux/sysctl.h>
|
#include <linux/sysctl.h>
|
||||||
#include <linux/input.h>
|
#include <linux/input.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/kbd_kern.h>
|
|
||||||
|
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
|
|
||||||
static struct input_dev *emumousebtn;
|
|
||||||
static int emumousebtn_input_register(void);
|
|
||||||
static int mouse_emulate_buttons;
|
static int mouse_emulate_buttons;
|
||||||
static int mouse_button2_keycode = KEY_RIGHTCTRL; /* right control key */
|
static int mouse_button2_keycode = KEY_RIGHTCTRL; /* right control key */
|
||||||
static int mouse_button3_keycode = KEY_RIGHTALT; /* right option key */
|
static int mouse_button3_keycode = KEY_RIGHTALT; /* right option key */
|
||||||
static int mouse_last_keycode;
|
|
||||||
|
|
||||||
#if defined(CONFIG_SYSCTL)
|
static struct input_dev *mac_hid_emumouse_dev;
|
||||||
|
|
||||||
|
static int mac_hid_create_emumouse(void)
|
||||||
|
{
|
||||||
|
static struct lock_class_key mac_hid_emumouse_dev_event_class;
|
||||||
|
static struct lock_class_key mac_hid_emumouse_dev_mutex_class;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
mac_hid_emumouse_dev = input_allocate_device();
|
||||||
|
if (!mac_hid_emumouse_dev)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
lockdep_set_class(&mac_hid_emumouse_dev->event_lock,
|
||||||
|
&mac_hid_emumouse_dev_event_class);
|
||||||
|
lockdep_set_class(&mac_hid_emumouse_dev->mutex,
|
||||||
|
&mac_hid_emumouse_dev_mutex_class);
|
||||||
|
|
||||||
|
mac_hid_emumouse_dev->name = "Macintosh mouse button emulation";
|
||||||
|
mac_hid_emumouse_dev->id.bustype = BUS_ADB;
|
||||||
|
mac_hid_emumouse_dev->id.vendor = 0x0001;
|
||||||
|
mac_hid_emumouse_dev->id.product = 0x0001;
|
||||||
|
mac_hid_emumouse_dev->id.version = 0x0100;
|
||||||
|
|
||||||
|
mac_hid_emumouse_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
|
||||||
|
mac_hid_emumouse_dev->keybit[BIT_WORD(BTN_MOUSE)] =
|
||||||
|
BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_MIDDLE) | BIT_MASK(BTN_RIGHT);
|
||||||
|
mac_hid_emumouse_dev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y);
|
||||||
|
|
||||||
|
err = input_register_device(mac_hid_emumouse_dev);
|
||||||
|
if (err) {
|
||||||
|
input_free_device(mac_hid_emumouse_dev);
|
||||||
|
mac_hid_emumouse_dev = NULL;
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mac_hid_destroy_emumouse(void)
|
||||||
|
{
|
||||||
|
input_unregister_device(mac_hid_emumouse_dev);
|
||||||
|
mac_hid_emumouse_dev = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool mac_hid_emumouse_filter(struct input_handle *handle,
|
||||||
|
unsigned int type, unsigned int code,
|
||||||
|
int value)
|
||||||
|
{
|
||||||
|
unsigned int btn;
|
||||||
|
|
||||||
|
if (type != EV_KEY)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (code == mouse_button2_keycode)
|
||||||
|
btn = BTN_MIDDLE;
|
||||||
|
else if (code == mouse_button3_keycode)
|
||||||
|
btn = BTN_RIGHT;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
|
||||||
|
input_report_key(mac_hid_emumouse_dev, btn, value);
|
||||||
|
input_sync(mac_hid_emumouse_dev);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mac_hid_emumouse_connect(struct input_handler *handler,
|
||||||
|
struct input_dev *dev,
|
||||||
|
const struct input_device_id *id)
|
||||||
|
{
|
||||||
|
struct input_handle *handle;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
/* Don't bind to ourselves */
|
||||||
|
if (dev == mac_hid_emumouse_dev)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL);
|
||||||
|
if (!handle)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
handle->dev = dev;
|
||||||
|
handle->handler = handler;
|
||||||
|
handle->name = "mac-button-emul";
|
||||||
|
|
||||||
|
error = input_register_handle(handle);
|
||||||
|
if (error) {
|
||||||
|
printk(KERN_ERR
|
||||||
|
"mac_hid: Failed to register button emulation handle, "
|
||||||
|
"error %d\n", error);
|
||||||
|
goto err_free;
|
||||||
|
}
|
||||||
|
|
||||||
|
error = input_open_device(handle);
|
||||||
|
if (error) {
|
||||||
|
printk(KERN_ERR
|
||||||
|
"mac_hid: Failed to open input device, error %d\n",
|
||||||
|
error);
|
||||||
|
goto err_unregister;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
err_unregister:
|
||||||
|
input_unregister_handle(handle);
|
||||||
|
err_free:
|
||||||
|
kfree(handle);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mac_hid_emumouse_disconnect(struct input_handle *handle)
|
||||||
|
{
|
||||||
|
input_close_device(handle);
|
||||||
|
input_unregister_handle(handle);
|
||||||
|
kfree(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct input_device_id mac_hid_emumouse_ids[] = {
|
||||||
|
{
|
||||||
|
.flags = INPUT_DEVICE_ID_MATCH_EVBIT,
|
||||||
|
.evbit = { BIT_MASK(EV_KEY) },
|
||||||
|
},
|
||||||
|
{ },
|
||||||
|
};
|
||||||
|
|
||||||
|
MODULE_DEVICE_TABLE(input, mac_hid_emumouse_ids);
|
||||||
|
|
||||||
|
static struct input_handler mac_hid_emumouse_handler = {
|
||||||
|
.filter = mac_hid_emumouse_filter,
|
||||||
|
.connect = mac_hid_emumouse_connect,
|
||||||
|
.disconnect = mac_hid_emumouse_disconnect,
|
||||||
|
.name = "mac-button-emul",
|
||||||
|
.id_table = mac_hid_emumouse_ids,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int mac_hid_start_emulation(void)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
|
||||||
|
err = mac_hid_create_emumouse();
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
err = input_register_handler(&mac_hid_emumouse_handler);
|
||||||
|
if (err) {
|
||||||
|
mac_hid_destroy_emumouse();
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mac_hid_stop_emulation(void)
|
||||||
|
{
|
||||||
|
input_unregister_handler(&mac_hid_emumouse_handler);
|
||||||
|
mac_hid_destroy_emumouse();
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mac_hid_toggle_emumouse(ctl_table *table, int write,
|
||||||
|
void __user *buffer, size_t *lenp,
|
||||||
|
loff_t *ppos)
|
||||||
|
{
|
||||||
|
int *valp = table->data;
|
||||||
|
int old_val = *valp;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
rc = proc_dointvec(table, write, buffer, lenp, ppos);
|
||||||
|
|
||||||
|
if (rc == 0 && write && *valp != old_val) {
|
||||||
|
if (*valp == 1)
|
||||||
|
rc = mac_hid_start_emulation();
|
||||||
|
else if (*valp == 0)
|
||||||
|
mac_hid_stop_emulation();
|
||||||
|
else
|
||||||
|
rc = -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Restore the old value in case of error */
|
||||||
|
if (rc)
|
||||||
|
*valp = old_val;
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
/* file(s) in /proc/sys/dev/mac_hid */
|
/* file(s) in /proc/sys/dev/mac_hid */
|
||||||
static ctl_table mac_hid_files[] = {
|
static ctl_table mac_hid_files[] = {
|
||||||
{
|
{
|
||||||
|
|
@ -31,7 +211,7 @@ static ctl_table mac_hid_files[] = {
|
||||||
.data = &mouse_emulate_buttons,
|
.data = &mouse_emulate_buttons,
|
||||||
.maxlen = sizeof(int),
|
.maxlen = sizeof(int),
|
||||||
.mode = 0644,
|
.mode = 0644,
|
||||||
.proc_handler = proc_dointvec,
|
.proc_handler = mac_hid_toggle_emumouse,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.procname = "mouse_button2_keycode",
|
.procname = "mouse_button2_keycode",
|
||||||
|
|
@ -74,75 +254,21 @@ static ctl_table mac_hid_root_dir[] = {
|
||||||
|
|
||||||
static struct ctl_table_header *mac_hid_sysctl_header;
|
static struct ctl_table_header *mac_hid_sysctl_header;
|
||||||
|
|
||||||
#endif /* endif CONFIG_SYSCTL */
|
|
||||||
|
|
||||||
int mac_hid_mouse_emulate_buttons(int caller, unsigned int keycode, int down)
|
|
||||||
{
|
|
||||||
switch (caller) {
|
|
||||||
case 1:
|
|
||||||
/* Called from keyboard.c */
|
|
||||||
if (mouse_emulate_buttons
|
|
||||||
&& (keycode == mouse_button2_keycode
|
|
||||||
|| keycode == mouse_button3_keycode)) {
|
|
||||||
if (mouse_emulate_buttons == 1) {
|
|
||||||
input_report_key(emumousebtn,
|
|
||||||
keycode == mouse_button2_keycode ? BTN_MIDDLE : BTN_RIGHT,
|
|
||||||
down);
|
|
||||||
input_sync(emumousebtn);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
mouse_last_keycode = down ? keycode : 0;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct lock_class_key emumousebtn_event_class;
|
|
||||||
static struct lock_class_key emumousebtn_mutex_class;
|
|
||||||
|
|
||||||
static int emumousebtn_input_register(void)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
emumousebtn = input_allocate_device();
|
|
||||||
if (!emumousebtn)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
lockdep_set_class(&emumousebtn->event_lock, &emumousebtn_event_class);
|
|
||||||
lockdep_set_class(&emumousebtn->mutex, &emumousebtn_mutex_class);
|
|
||||||
|
|
||||||
emumousebtn->name = "Macintosh mouse button emulation";
|
|
||||||
emumousebtn->id.bustype = BUS_ADB;
|
|
||||||
emumousebtn->id.vendor = 0x0001;
|
|
||||||
emumousebtn->id.product = 0x0001;
|
|
||||||
emumousebtn->id.version = 0x0100;
|
|
||||||
|
|
||||||
emumousebtn->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
|
|
||||||
emumousebtn->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) |
|
|
||||||
BIT_MASK(BTN_MIDDLE) | BIT_MASK(BTN_RIGHT);
|
|
||||||
emumousebtn->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y);
|
|
||||||
|
|
||||||
ret = input_register_device(emumousebtn);
|
|
||||||
if (ret)
|
|
||||||
input_free_device(emumousebtn);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int __init mac_hid_init(void)
|
static int __init mac_hid_init(void)
|
||||||
{
|
{
|
||||||
int err;
|
|
||||||
|
|
||||||
err = emumousebtn_input_register();
|
|
||||||
if (err)
|
|
||||||
return err;
|
|
||||||
|
|
||||||
#if defined(CONFIG_SYSCTL)
|
|
||||||
mac_hid_sysctl_header = register_sysctl_table(mac_hid_root_dir);
|
mac_hid_sysctl_header = register_sysctl_table(mac_hid_root_dir);
|
||||||
#endif /* CONFIG_SYSCTL */
|
if (!mac_hid_sysctl_header)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
module_init(mac_hid_init);
|
||||||
|
|
||||||
device_initcall(mac_hid_init);
|
static void __exit mac_hid_exit(void)
|
||||||
|
{
|
||||||
|
unregister_sysctl_table(mac_hid_sysctl_header);
|
||||||
|
|
||||||
|
if (mouse_emulate_buttons)
|
||||||
|
mac_hid_stop_emulation();
|
||||||
|
}
|
||||||
|
module_exit(mac_hid_exit);
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,6 @@ struct gameport {
|
||||||
struct mutex drv_mutex; /* protects serio->drv so attributes can pin driver */
|
struct mutex drv_mutex; /* protects serio->drv so attributes can pin driver */
|
||||||
|
|
||||||
struct device dev;
|
struct device dev;
|
||||||
unsigned int registered; /* port has been fully registered with driver core */
|
|
||||||
|
|
||||||
struct list_head node;
|
struct list_head node;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ struct gpio_keys_button {
|
||||||
int type; /* input event type (EV_KEY, EV_SW) */
|
int type; /* input event type (EV_KEY, EV_SW) */
|
||||||
int wakeup; /* configure the button as a wake-up source */
|
int wakeup; /* configure the button as a wake-up source */
|
||||||
int debounce_interval; /* debounce ticks interval in msecs */
|
int debounce_interval; /* debounce ticks interval in msecs */
|
||||||
|
bool can_disable;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct gpio_keys_platform_data {
|
struct gpio_keys_platform_data {
|
||||||
|
|
|
||||||
|
|
@ -378,7 +378,7 @@ struct input_absinfo {
|
||||||
#define KEY_WIMAX 246
|
#define KEY_WIMAX 246
|
||||||
#define KEY_RFKILL 247 /* Key that controls all radios */
|
#define KEY_RFKILL 247 /* Key that controls all radios */
|
||||||
|
|
||||||
/* Range 248 - 255 is reserved for special needs of AT keyboard driver */
|
/* Code 255 is reserved for special needs of AT keyboard driver */
|
||||||
|
|
||||||
#define BTN_MISC 0x100
|
#define BTN_MISC 0x100
|
||||||
#define BTN_0 0x100
|
#define BTN_0 0x100
|
||||||
|
|
@ -597,6 +597,7 @@ struct input_absinfo {
|
||||||
#define KEY_NUMERIC_POUND 0x20b
|
#define KEY_NUMERIC_POUND 0x20b
|
||||||
|
|
||||||
#define KEY_CAMERA_FOCUS 0x210
|
#define KEY_CAMERA_FOCUS 0x210
|
||||||
|
#define KEY_WPS_BUTTON 0x211 /* WiFi Protected Setup key */
|
||||||
|
|
||||||
#define BTN_TRIGGER_HAPPY 0x2c0
|
#define BTN_TRIGGER_HAPPY 0x2c0
|
||||||
#define BTN_TRIGGER_HAPPY1 0x2c0
|
#define BTN_TRIGGER_HAPPY1 0x2c0
|
||||||
|
|
@ -1242,6 +1243,10 @@ struct input_handle;
|
||||||
* @event: event handler. This method is being called by input core with
|
* @event: event handler. This method is being called by input core with
|
||||||
* interrupts disabled and dev->event_lock spinlock held and so
|
* interrupts disabled and dev->event_lock spinlock held and so
|
||||||
* it may not sleep
|
* it may not sleep
|
||||||
|
* @filter: similar to @event; separates normal event handlers from
|
||||||
|
* "filters".
|
||||||
|
* @match: called after comparing device's id with handler's id_table
|
||||||
|
* to perform fine-grained matching between device and handler
|
||||||
* @connect: called when attaching a handler to an input device
|
* @connect: called when attaching a handler to an input device
|
||||||
* @disconnect: disconnects a handler from input device
|
* @disconnect: disconnects a handler from input device
|
||||||
* @start: starts handler for given handle. This function is called by
|
* @start: starts handler for given handle. This function is called by
|
||||||
|
|
@ -1253,8 +1258,6 @@ struct input_handle;
|
||||||
* @name: name of the handler, to be shown in /proc/bus/input/handlers
|
* @name: name of the handler, to be shown in /proc/bus/input/handlers
|
||||||
* @id_table: pointer to a table of input_device_ids this driver can
|
* @id_table: pointer to a table of input_device_ids this driver can
|
||||||
* handle
|
* handle
|
||||||
* @blacklist: pointer to a table of input_device_ids this driver should
|
|
||||||
* ignore even if they match @id_table
|
|
||||||
* @h_list: list of input handles associated with the handler
|
* @h_list: list of input handles associated with the handler
|
||||||
* @node: for placing the driver onto input_handler_list
|
* @node: for placing the driver onto input_handler_list
|
||||||
*
|
*
|
||||||
|
|
@ -1263,6 +1266,11 @@ struct input_handle;
|
||||||
* same time. All of them will get their copy of input event generated by
|
* same time. All of them will get their copy of input event generated by
|
||||||
* the device.
|
* the device.
|
||||||
*
|
*
|
||||||
|
* The very same structure is used to implement input filters. Input core
|
||||||
|
* allows filters to run first and will not pass event to regular handlers
|
||||||
|
* if any of the filters indicate that the event should be filtered (by
|
||||||
|
* returning %true from their filter() method).
|
||||||
|
*
|
||||||
* Note that input core serializes calls to connect() and disconnect()
|
* Note that input core serializes calls to connect() and disconnect()
|
||||||
* methods.
|
* methods.
|
||||||
*/
|
*/
|
||||||
|
|
@ -1271,6 +1279,8 @@ struct input_handler {
|
||||||
void *private;
|
void *private;
|
||||||
|
|
||||||
void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value);
|
void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value);
|
||||||
|
bool (*filter)(struct input_handle *handle, unsigned int type, unsigned int code, int value);
|
||||||
|
bool (*match)(struct input_handler *handler, struct input_dev *dev);
|
||||||
int (*connect)(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id);
|
int (*connect)(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id);
|
||||||
void (*disconnect)(struct input_handle *handle);
|
void (*disconnect)(struct input_handle *handle);
|
||||||
void (*start)(struct input_handle *handle);
|
void (*start)(struct input_handle *handle);
|
||||||
|
|
@ -1280,7 +1290,6 @@ struct input_handler {
|
||||||
const char *name;
|
const char *name;
|
||||||
|
|
||||||
const struct input_device_id *id_table;
|
const struct input_device_id *id_table;
|
||||||
const struct input_device_id *blacklist;
|
|
||||||
|
|
||||||
struct list_head h_list;
|
struct list_head h_list;
|
||||||
struct list_head node;
|
struct list_head node;
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,15 @@
|
||||||
#ifndef __SH_KEYSC_H__
|
#ifndef __SH_KEYSC_H__
|
||||||
#define __SH_KEYSC_H__
|
#define __SH_KEYSC_H__
|
||||||
|
|
||||||
#define SH_KEYSC_MAXKEYS 30
|
#define SH_KEYSC_MAXKEYS 49
|
||||||
|
|
||||||
struct sh_keysc_info {
|
struct sh_keysc_info {
|
||||||
enum { SH_KEYSC_MODE_1, SH_KEYSC_MODE_2, SH_KEYSC_MODE_3 } mode;
|
enum { SH_KEYSC_MODE_1, SH_KEYSC_MODE_2, SH_KEYSC_MODE_3,
|
||||||
|
SH_KEYSC_MODE_4, SH_KEYSC_MODE_5, SH_KEYSC_MODE_6 } mode;
|
||||||
int scan_timing; /* 0 -> 7, see KYCR1, SCN[2:0] */
|
int scan_timing; /* 0 -> 7, see KYCR1, SCN[2:0] */
|
||||||
int delay;
|
int delay;
|
||||||
int kycr2_delay;
|
int kycr2_delay;
|
||||||
int keycodes[SH_KEYSC_MAXKEYS];
|
int keycodes[SH_KEYSC_MAXKEYS]; /* KEYIN * KEYOUT */
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* __SH_KEYSC_H__ */
|
#endif /* __SH_KEYSC_H__ */
|
||||||
|
|
|
||||||
|
|
@ -161,7 +161,4 @@ static inline void con_schedule_flip(struct tty_struct *t)
|
||||||
schedule_delayed_work(&t->buf.work, 0);
|
schedule_delayed_work(&t->buf.work, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* mac_hid.c */
|
|
||||||
extern int mac_hid_mouse_emulate_buttons(int, unsigned int, int);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,6 @@ struct serio {
|
||||||
char phys[32];
|
char phys[32];
|
||||||
|
|
||||||
bool manual_bind;
|
bool manual_bind;
|
||||||
bool registered; /* port has been fully registered with driver core */
|
|
||||||
|
|
||||||
struct serio_device_id id;
|
struct serio_device_id id;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue