Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
7f93220b
Commit
7f93220b
authored
Sep 10, 2005
by
Linus Torvalds
Browse files
Options
Browse Files
Download
Plain Diff
Merge master.kernel.org:/pub/scm/linux/kernel/git/dtor/input
parents
2b8dfec8
d39969de
Changes
26
Hide whitespace changes
Inline
Side-by-side
Showing
26 changed files
with
986 additions
and
312 deletions
+986
-312
Documentation/kernel-parameters.txt
Documentation/kernel-parameters.txt
+1
-0
drivers/char/keyboard.c
drivers/char/keyboard.c
+56
-55
drivers/input/evdev.c
drivers/input/evdev.c
+1
-1
drivers/input/joystick/iforce/iforce-packets.c
drivers/input/joystick/iforce/iforce-packets.c
+7
-25
drivers/input/joystick/iforce/iforce-usb.c
drivers/input/joystick/iforce/iforce-usb.c
+1
-0
drivers/input/keyboard/atkbd.c
drivers/input/keyboard/atkbd.c
+7
-3
drivers/input/keyboard/sunkbd.c
drivers/input/keyboard/sunkbd.c
+1
-1
drivers/input/mouse/Makefile
drivers/input/mouse/Makefile
+1
-1
drivers/input/mouse/alps.c
drivers/input/mouse/alps.c
+1
-1
drivers/input/mouse/logips2pp.c
drivers/input/mouse/logips2pp.c
+8
-5
drivers/input/mouse/psmouse-base.c
drivers/input/mouse/psmouse-base.c
+80
-52
drivers/input/mouse/psmouse.h
drivers/input/mouse/psmouse.h
+33
-19
drivers/input/mouse/trackpoint.c
drivers/input/mouse/trackpoint.c
+304
-0
drivers/input/mouse/trackpoint.h
drivers/input/mouse/trackpoint.h
+147
-0
drivers/input/serio/i8042-io.h
drivers/input/serio/i8042-io.h
+3
-3
drivers/input/serio/i8042-ip22io.h
drivers/input/serio/i8042-ip22io.h
+1
-1
drivers/input/serio/i8042-jazzio.h
drivers/input/serio/i8042-jazzio.h
+1
-1
drivers/input/serio/i8042-sparcio.h
drivers/input/serio/i8042-sparcio.h
+6
-6
drivers/input/serio/i8042-x86ia64io.h
drivers/input/serio/i8042-x86ia64io.h
+47
-25
drivers/input/serio/i8042.c
drivers/input/serio/i8042.c
+118
-81
drivers/usb/input/hid-core.c
drivers/usb/input/hid-core.c
+55
-21
drivers/usb/input/hid-debug.h
drivers/usb/input/hid-debug.h
+28
-6
drivers/usb/input/hid-input.c
drivers/usb/input/hid-input.c
+62
-4
drivers/usb/input/hid.h
drivers/usb/input/hid.h
+8
-1
drivers/usb/input/hiddev.c
drivers/usb/input/hiddev.c
+1
-0
include/linux/input.h
include/linux/input.h
+8
-0
No files found.
Documentation/kernel-parameters.txt
View file @
7f93220b
...
...
@@ -549,6 +549,7 @@ running once the system is up.
keyboard and can not control its state
(Don't attempt to blink the leds)
i8042.noaux [HW] Don't check for auxiliary (== mouse) port
i8042.nokbd [HW] Don't check/create keyboard port
i8042.nomux [HW] Don't check presence of an active multiplexing
controller
i8042.nopnp [HW] Don't use ACPIPnP / PnPBIOS to discover KBD/AUX
...
...
drivers/char/keyboard.c
View file @
7f93220b
...
...
@@ -14,7 +14,7 @@
* `Sticky' modifier keys, 951006.
*
* 11-11-96: SAK should now work in the raw mode (Martin Mares)
*
*
* Modified to provide 'generic' keyboard support by Hamish Macdonald
* Merge with the m68k keyboard driver and split-off of the PC low-level
* parts by Geert Uytterhoeven, May 1997
...
...
@@ -52,7 +52,7 @@ extern void ctrl_alt_del(void);
/*
* Some laptops take the 789uiojklm,. keys as number pad when NumLock is on.
* This seems a good reason to start with NumLock off. On HIL keyboards
* of PARISC machines however there is no NumLock key and everyone expects the keypad
* of PARISC machines however there is no NumLock key and everyone expects the keypad
* to be used for numbers.
*/
...
...
@@ -76,17 +76,17 @@ void compute_shiftstate(void);
k_meta, k_ascii, k_lock, k_lowercase,\
k_slock, k_dead2, k_ignore, k_ignore
typedef
void
(
k_handler_fn
)(
struct
vc_data
*
vc
,
unsigned
char
value
,
typedef
void
(
k_handler_fn
)(
struct
vc_data
*
vc
,
unsigned
char
value
,
char
up_flag
,
struct
pt_regs
*
regs
);
static
k_handler_fn
K_HANDLERS
;
static
k_handler_fn
*
k_handler
[
16
]
=
{
K_HANDLERS
};
#define FN_HANDLERS\
fn_null,
fn_enter, fn_show_ptregs, fn_show_mem,\
fn_show_state, fn_send_intr,
fn_lastcons,
fn_caps_toggle,\
fn_num, fn_hold,
fn_scroll_forw, fn_scroll_back,\
fn_boot_it,
fn_caps_on,
fn_compose, fn_SAK,\
fn_dec_console, fn_inc_console, fn_spawn_con,
fn_bare_num
fn_null, fn_enter, fn_show_ptregs, fn_show_mem,\
fn_show_state, fn_send_intr,
fn_lastcons,
fn_caps_toggle,\
fn_num, fn_hold, fn_scroll_forw, fn_scroll_back,\
fn_boot_it,
fn_caps_on,
fn_compose, fn_SAK,\
fn_dec_console, fn_inc_console, fn_spawn_con, fn_bare_num
typedef
void
(
fn_handler_fn
)(
struct
vc_data
*
vc
,
struct
pt_regs
*
regs
);
static
fn_handler_fn
FN_HANDLERS
;
...
...
@@ -159,13 +159,13 @@ static int sysrq_alt;
*/
int
getkeycode
(
unsigned
int
scancode
)
{
struct
list_head
*
node
;
struct
list_head
*
node
;
struct
input_dev
*
dev
=
NULL
;
list_for_each
(
node
,
&
kbd_handler
.
h_list
)
{
struct
input_handle
*
handle
=
to_handle_h
(
node
);
if
(
handle
->
dev
->
keycodesize
)
{
dev
=
handle
->
dev
;
list_for_each
(
node
,
&
kbd_handler
.
h_list
)
{
struct
input_handle
*
handle
=
to_handle_h
(
node
);
if
(
handle
->
dev
->
keycodesize
)
{
dev
=
handle
->
dev
;
break
;
}
}
...
...
@@ -181,15 +181,15 @@ int getkeycode(unsigned int scancode)
int
setkeycode
(
unsigned
int
scancode
,
unsigned
int
keycode
)
{
struct
list_head
*
node
;
struct
list_head
*
node
;
struct
input_dev
*
dev
=
NULL
;
unsigned
int
i
,
oldkey
;
list_for_each
(
node
,
&
kbd_handler
.
h_list
)
{
list_for_each
(
node
,
&
kbd_handler
.
h_list
)
{
struct
input_handle
*
handle
=
to_handle_h
(
node
);
if
(
handle
->
dev
->
keycodesize
)
{
dev
=
handle
->
dev
;
break
;
if
(
handle
->
dev
->
keycodesize
)
{
dev
=
handle
->
dev
;
break
;
}
}
...
...
@@ -200,7 +200,7 @@ int setkeycode(unsigned int scancode, unsigned int keycode)
return
-
EINVAL
;
if
(
keycode
<
0
||
keycode
>
KEY_MAX
)
return
-
EINVAL
;
if
(
keycode
>>
(
dev
->
keycodesize
*
8
))
if
(
dev
->
keycodesize
<
sizeof
(
keycode
)
&&
(
keycode
>>
(
dev
->
keycodesize
*
8
)
))
return
-
EINVAL
;
oldkey
=
SET_INPUT_KEYCODE
(
dev
,
scancode
,
keycode
);
...
...
@@ -216,11 +216,11 @@ int setkeycode(unsigned int scancode, unsigned int keycode)
}
/*
* Making beeps and bells.
* Making beeps and bells.
*/
static
void
kd_nosound
(
unsigned
long
ignored
)
{
struct
list_head
*
node
;
struct
list_head
*
node
;
list_for_each
(
node
,
&
kbd_handler
.
h_list
)
{
struct
input_handle
*
handle
=
to_handle_h
(
node
);
...
...
@@ -237,12 +237,12 @@ static DEFINE_TIMER(kd_mksound_timer, kd_nosound, 0, 0);
void
kd_mksound
(
unsigned
int
hz
,
unsigned
int
ticks
)
{
struct
list_head
*
node
;
struct
list_head
*
node
;
del_timer
(
&
kd_mksound_timer
);
if
(
hz
)
{
list_for_each_prev
(
node
,
&
kbd_handler
.
h_list
)
{
list_for_each_prev
(
node
,
&
kbd_handler
.
h_list
)
{
struct
input_handle
*
handle
=
to_handle_h
(
node
);
if
(
test_bit
(
EV_SND
,
handle
->
dev
->
evbit
))
{
if
(
test_bit
(
SND_TONE
,
handle
->
dev
->
sndbit
))
{
...
...
@@ -337,19 +337,19 @@ static void to_utf8(struct vc_data *vc, ushort c)
if
(
c
<
0x80
)
/* 0******* */
put_queue
(
vc
,
c
);
else
if
(
c
<
0x800
)
{
else
if
(
c
<
0x800
)
{
/* 110***** 10****** */
put_queue
(
vc
,
0xc0
|
(
c
>>
6
));
put_queue
(
vc
,
0xc0
|
(
c
>>
6
));
put_queue
(
vc
,
0x80
|
(
c
&
0x3f
));
}
else
{
}
else
{
/* 1110**** 10****** 10****** */
put_queue
(
vc
,
0xe0
|
(
c
>>
12
));
put_queue
(
vc
,
0x80
|
((
c
>>
6
)
&
0x3f
));
put_queue
(
vc
,
0x80
|
(
c
&
0x3f
));
}
}
}
/*
/*
* Called after returning from RAW mode or when changing consoles - recompute
* shift_down[] and shift_state from key_down[] maybe called when keymap is
* undefined, so that shiftkey release is seen
...
...
@@ -360,7 +360,7 @@ void compute_shiftstate(void)
shift_state
=
0
;
memset
(
shift_down
,
0
,
sizeof
(
shift_down
));
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
key_down
);
i
++
)
{
if
(
!
key_down
[
i
])
...
...
@@ -499,9 +499,9 @@ static void fn_dec_console(struct vc_data *vc, struct pt_regs *regs)
if
(
want_console
!=
-
1
)
cur
=
want_console
;
for
(
i
=
cur
-
1
;
i
!=
cur
;
i
--
)
{
for
(
i
=
cur
-
1
;
i
!=
cur
;
i
--
)
{
if
(
i
==
-
1
)
i
=
MAX_NR_CONSOLES
-
1
;
i
=
MAX_NR_CONSOLES
-
1
;
if
(
vc_cons_allocated
(
i
))
break
;
}
...
...
@@ -567,9 +567,9 @@ static void fn_compose(struct vc_data *vc, struct pt_regs *regs)
static
void
fn_spawn_con
(
struct
vc_data
*
vc
,
struct
pt_regs
*
regs
)
{
if
(
spawnpid
)
if
(
kill_proc
(
spawnpid
,
spawnsig
,
1
))
spawnpid
=
0
;
if
(
spawnpid
)
if
(
kill_proc
(
spawnpid
,
spawnsig
,
1
))
spawnpid
=
0
;
}
static
void
fn_SAK
(
struct
vc_data
*
vc
,
struct
pt_regs
*
regs
)
...
...
@@ -603,8 +603,8 @@ static void k_spec(struct vc_data *vc, unsigned char value, char up_flag, struct
return
;
if
(
value
>=
ARRAY_SIZE
(
fn_handler
))
return
;
if
((
kbd
->
kbdmode
==
VC_RAW
||
kbd
->
kbdmode
==
VC_MEDIUMRAW
)
&&
if
((
kbd
->
kbdmode
==
VC_RAW
||
kbd
->
kbdmode
==
VC_MEDIUMRAW
)
&&
value
!=
KVAL
(
K_SAK
))
return
;
/* SAK is allowed even in raw mode */
fn_handler
[
value
](
vc
,
regs
);
...
...
@@ -894,11 +894,11 @@ static inline unsigned char getleds(void)
static
void
kbd_bh
(
unsigned
long
dummy
)
{
struct
list_head
*
node
;
struct
list_head
*
node
;
unsigned
char
leds
=
getleds
();
if
(
leds
!=
ledstate
)
{
list_for_each
(
node
,
&
kbd_handler
.
h_list
)
{
list_for_each
(
node
,
&
kbd_handler
.
h_list
)
{
struct
input_handle
*
handle
=
to_handle_h
(
node
);
input_event
(
handle
->
dev
,
EV_LED
,
LED_SCROLLL
,
!!
(
leds
&
0x01
));
input_event
(
handle
->
dev
,
EV_LED
,
LED_NUML
,
!!
(
leds
&
0x02
));
...
...
@@ -963,11 +963,11 @@ static int sparc_l1_a_state = 0;
extern
void
sun_do_break
(
void
);
#endif
static
int
emulate_raw
(
struct
vc_data
*
vc
,
unsigned
int
keycode
,
static
int
emulate_raw
(
struct
vc_data
*
vc
,
unsigned
int
keycode
,
unsigned
char
up_flag
)
{
if
(
keycode
>
255
||
!
x86_keycodes
[
keycode
])
return
-
1
;
return
-
1
;
switch
(
keycode
)
{
case
KEY_PAUSE
:
...
...
@@ -981,7 +981,7 @@ static int emulate_raw(struct vc_data *vc, unsigned int keycode,
case
KEY_HANJA
:
if
(
!
up_flag
)
put_queue
(
vc
,
0xf2
);
return
0
;
}
}
if
(
keycode
==
KEY_SYSRQ
&&
sysrq_alt
)
{
put_queue
(
vc
,
0x54
|
up_flag
);
...
...
@@ -1104,11 +1104,12 @@ static void kbd_keycode(unsigned int keycode, int down,
else
clear_bit
(
keycode
,
key_down
);
if
(
rep
&&
(
!
vc_kbd_mode
(
kbd
,
VC_REPEAT
)
||
(
tty
&&
(
!
L_ECHO
(
tty
)
&&
tty
->
driver
->
chars_in_buffer
(
tty
)))))
{
if
(
rep
&&
(
!
vc_kbd_mode
(
kbd
,
VC_REPEAT
)
||
(
tty
&&
!
L_ECHO
(
tty
)
&&
tty
->
driver
->
chars_in_buffer
(
tty
))))
{
/*
* Don't repeat a key if the input buffers are not empty and the
* characters get aren't echoed locally. This makes key repeat
* characters get aren't echoed locally. This makes key repeat
* usable with slow applications and under heavy loads.
*/
return
;
...
...
@@ -1130,7 +1131,8 @@ static void kbd_keycode(unsigned int keycode, int down,
type
=
KTYP
(
keysym
);
if
(
type
<
0xf0
)
{
if
(
down
&&
!
raw_mode
)
to_utf8
(
vc
,
keysym
);
if
(
down
&&
!
raw_mode
)
to_utf8
(
vc
,
keysym
);
return
;
}
...
...
@@ -1154,7 +1156,7 @@ static void kbd_keycode(unsigned int keycode, int down,
kbd
->
slockstate
=
0
;
}
static
void
kbd_event
(
struct
input_handle
*
handle
,
unsigned
int
event_type
,
static
void
kbd_event
(
struct
input_handle
*
handle
,
unsigned
int
event_type
,
unsigned
int
event_code
,
int
value
)
{
if
(
event_type
==
EV_MSC
&&
event_code
==
MSC_RAW
&&
HW_RAW
(
handle
->
dev
))
...
...
@@ -1166,15 +1168,13 @@ static void kbd_event(struct input_handle *handle, unsigned int event_type,
schedule_console_callback
();
}
static
char
kbd_name
[]
=
"kbd"
;
/*
* 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
* likes it, it can open it and get events from it. In this (kbd_connect)
* function, we should decide which VT to bind that keyboard to initially.
*/
static
struct
input_handle
*
kbd_connect
(
struct
input_handler
*
handler
,
static
struct
input_handle
*
kbd_connect
(
struct
input_handler
*
handler
,
struct
input_dev
*
dev
,
struct
input_device_id
*
id
)
{
...
...
@@ -1182,18 +1182,19 @@ static struct input_handle *kbd_connect(struct input_handler *handler,
int
i
;
for
(
i
=
KEY_RESERVED
;
i
<
BTN_MISC
;
i
++
)
if
(
test_bit
(
i
,
dev
->
keybit
))
break
;
if
(
test_bit
(
i
,
dev
->
keybit
))
break
;
if
(
(
i
==
BTN_MISC
)
&&
!
test_bit
(
EV_SND
,
dev
->
evbit
))
if
(
i
==
BTN_MISC
&&
!
test_bit
(
EV_SND
,
dev
->
evbit
))
return
NULL
;
if
(
!
(
handle
=
kmalloc
(
sizeof
(
struct
input_handle
),
GFP_KERNEL
)))
if
(
!
(
handle
=
kmalloc
(
sizeof
(
struct
input_handle
),
GFP_KERNEL
)))
return
NULL
;
memset
(
handle
,
0
,
sizeof
(
struct
input_handle
));
handle
->
dev
=
dev
;
handle
->
handler
=
handler
;
handle
->
name
=
kbd_name
;
handle
->
name
=
"kbd"
;
input_open_device
(
handle
);
kbd_refresh_leds
(
handle
);
...
...
@@ -1212,11 +1213,11 @@ static struct input_device_id kbd_ids[] = {
.
flags
=
INPUT_DEVICE_ID_MATCH_EVBIT
,
.
evbit
=
{
BIT
(
EV_KEY
)
},
},
{
.
flags
=
INPUT_DEVICE_ID_MATCH_EVBIT
,
.
evbit
=
{
BIT
(
EV_SND
)
},
},
},
{
},
/* Terminating entry */
};
...
...
drivers/input/evdev.c
View file @
7f93220b
...
...
@@ -322,7 +322,7 @@ static long evdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
if
(
t
<
0
||
t
>=
dev
->
keycodemax
||
!
dev
->
keycodesize
)
return
-
EINVAL
;
if
(
get_user
(
v
,
ip
+
1
))
return
-
EFAULT
;
if
(
v
<
0
||
v
>
KEY_MAX
)
return
-
EINVAL
;
if
(
v
>>
(
dev
->
keycodesize
*
8
))
return
-
EINVAL
;
if
(
dev
->
keycodesize
<
sizeof
(
v
)
&&
(
v
>>
(
dev
->
keycodesize
*
8
)
))
return
-
EINVAL
;
u
=
SET_INPUT_KEYCODE
(
dev
,
t
,
v
);
clear_bit
(
u
,
dev
->
keybit
);
set_bit
(
v
,
dev
->
keybit
);
...
...
drivers/input/joystick/iforce/iforce-packets.c
View file @
7f93220b
...
...
@@ -249,9 +249,6 @@ void iforce_process_packet(struct iforce *iforce, u16 cmd, unsigned char *data,
int
iforce_get_id_packet
(
struct
iforce
*
iforce
,
char
*
packet
)
{
DECLARE_WAITQUEUE
(
wait
,
current
);
int
timeout
=
HZ
;
/* 1 second */
switch
(
iforce
->
bus
)
{
case
IFORCE_USB
:
...
...
@@ -260,22 +257,13 @@ int iforce_get_id_packet(struct iforce *iforce, char *packet)
iforce
->
cr
.
bRequest
=
packet
[
0
];
iforce
->
ctrl
->
dev
=
iforce
->
usbdev
;
set_current_state
(
TASK_INTERRUPTIBLE
);
add_wait_queue
(
&
iforce
->
wait
,
&
wait
);
if
(
usb_submit_urb
(
iforce
->
ctrl
,
GFP_ATOMIC
))
{
set_current_state
(
TASK_RUNNING
);
remove_wait_queue
(
&
iforce
->
wait
,
&
wait
);
if
(
usb_submit_urb
(
iforce
->
ctrl
,
GFP_ATOMIC
))
return
-
1
;
}
w
hile
(
timeout
&&
iforce
->
ctrl
->
status
==
-
EINPROGRESS
)
timeout
=
schedule_timeout
(
timeout
);
w
ait_event_interruptible_timeout
(
iforce
->
wait
,
iforce
->
ctrl
->
status
!=
-
EINPROGRESS
,
HZ
);
set_current_state
(
TASK_RUNNING
);
remove_wait_queue
(
&
iforce
->
wait
,
&
wait
);
if
(
!
timeout
)
{
if
(
iforce
->
ctrl
->
status
!=
-
EINPROGRESS
)
{
usb_unlink_urb
(
iforce
->
ctrl
);
return
-
1
;
}
...
...
@@ -290,16 +278,10 @@ int iforce_get_id_packet(struct iforce *iforce, char *packet)
iforce
->
expect_packet
=
FF_CMD_QUERY
;
iforce_send_packet
(
iforce
,
FF_CMD_QUERY
,
packet
);
set_current_state
(
TASK_INTERRUPTIBLE
);
add_wait_queue
(
&
iforce
->
wait
,
&
wait
);
while
(
timeout
&&
iforce
->
expect_packet
)
timeout
=
schedule_timeout
(
timeout
);
set_current_state
(
TASK_RUNNING
);
remove_wait_queue
(
&
iforce
->
wait
,
&
wait
);
wait_event_interruptible_timeout
(
iforce
->
wait
,
!
iforce
->
expect_packet
,
HZ
);
if
(
!
timeou
t
)
{
if
(
iforce
->
expect_packe
t
)
{
iforce
->
expect_packet
=
0
;
return
-
1
;
}
...
...
drivers/input/joystick/iforce/iforce-usb.c
View file @
7f93220b
...
...
@@ -95,6 +95,7 @@ static void iforce_usb_irq(struct urb *urb, struct pt_regs *regs)
goto
exit
;
}
wake_up
(
&
iforce
->
wait
);
iforce_process_packet
(
iforce
,
(
iforce
->
data
[
0
]
<<
8
)
|
(
urb
->
actual_length
-
1
),
iforce
->
data
+
1
,
regs
);
...
...
drivers/input/keyboard/atkbd.c
View file @
7f93220b
...
...
@@ -208,6 +208,7 @@ struct atkbd {
unsigned
char
resend
;
unsigned
char
release
;
unsigned
char
bat_xl
;
unsigned
char
err_xl
;
unsigned
int
last
;
unsigned
long
time
;
};
...
...
@@ -296,15 +297,18 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
if
(
atkbd
->
emul
||
!
(
code
==
ATKBD_RET_EMUL0
||
code
==
ATKBD_RET_EMUL1
||
code
==
ATKBD_RET_HANGUEL
||
code
==
ATKBD_RET_HANJA
||
code
==
ATKBD_RET_ERR
||
(
code
==
ATKBD_RET_ERR
&&
!
atkbd
->
err_xl
)
||
(
code
==
ATKBD_RET_BAT
&&
!
atkbd
->
bat_xl
)))
{
atkbd
->
release
=
code
>>
7
;
code
&=
0x7f
;
}
if
(
!
atkbd
->
emul
&&
(
code
&
0x7f
)
==
(
ATKBD_RET_BAT
&
0x7f
))
if
(
!
atkbd
->
emul
)
{
if
(
(
code
&
0x7f
)
==
(
ATKBD_RET_BAT
&
0x7f
))
atkbd
->
bat_xl
=
!
atkbd
->
release
;
if
((
code
&
0x7f
)
==
(
ATKBD_RET_ERR
&
0x7f
))
atkbd
->
err_xl
=
!
atkbd
->
release
;
}
}
switch
(
code
)
{
...
...
drivers/input/keyboard/sunkbd.c
View file @
7f93220b
...
...
@@ -44,7 +44,7 @@ MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE
(
"GPL"
);
static
unsigned
char
sunkbd_keycode
[
128
]
=
{
0
,
128
,
114
,
129
,
115
,
59
,
60
,
68
,
61
,
87
,
62
,
88
,
63
,
100
,
64
,
0
,
0
,
128
,
114
,
129
,
115
,
59
,
60
,
68
,
61
,
87
,
62
,
88
,
63
,
100
,
64
,
112
,
65
,
66
,
67
,
56
,
103
,
119
,
99
,
70
,
105
,
130
,
131
,
108
,
106
,
1
,
2
,
3
,
4
,
5
,
6
,
7
,
8
,
9
,
10
,
11
,
12
,
13
,
41
,
14
,
110
,
113
,
98
,
55
,
116
,
132
,
83
,
133
,
102
,
15
,
16
,
17
,
18
,
19
,
20
,
21
,
22
,
23
,
24
,
25
,
...
...
drivers/input/mouse/Makefile
View file @
7f93220b
...
...
@@ -15,4 +15,4 @@ obj-$(CONFIG_MOUSE_SERIAL) += sermouse.o
obj-$(CONFIG_MOUSE_HIL)
+=
hil_ptr.o
obj-$(CONFIG_MOUSE_VSXXXAA)
+=
vsxxxaa.o
psmouse-objs
:=
psmouse-base.o alps.o logips2pp.o synaptics.o lifebook.o
psmouse-objs
:=
psmouse-base.o alps.o logips2pp.o synaptics.o lifebook.o
trackpoint.o
drivers/input/mouse/alps.c
View file @
7f93220b
...
...
@@ -170,7 +170,7 @@ static void alps_process_packet(struct psmouse *psmouse, struct pt_regs *regs)
input_report_key
(
dev
,
BTN_TOOL_FINGER
,
z
>
0
);
if
(
priv
->
i
->
flags
&
ALPS_WHEEL
)
input_report_rel
(
dev
,
REL_WHEEL
,
((
packet
[
0
]
>>
4
)
&
0x07
)
|
((
packet
[
2
]
>>
2
)
&
0x08
));
input_report_rel
(
dev
,
REL_WHEEL
,
((
packet
[
2
]
<<
1
)
&
0x08
)
-
((
packet
[
0
]
>>
4
)
&
0x07
));
if
(
priv
->
i
->
flags
&
(
ALPS_FW_BK_1
|
ALPS_FW_BK_2
))
{
input_report_key
(
dev
,
BTN_FORWARD
,
forward
);
...
...
drivers/input/mouse/logips2pp.c
View file @
7f93220b
...
...
@@ -150,12 +150,12 @@ static void ps2pp_set_smartscroll(struct psmouse *psmouse, unsigned int smartscr
ps2_command
(
ps2dev
,
param
,
PSMOUSE_CMD_SETRES
);
}
static
ssize_t
ps
mouse_attr_show_smartscroll
(
struct
psmouse
*
psmouse
,
char
*
buf
)
static
ssize_t
ps
2pp_attr_show_smartscroll
(
struct
psmouse
*
psmouse
,
void
*
data
,
char
*
buf
)
{
return
sprintf
(
buf
,
"%d
\n
"
,
psmouse
->
smartscroll
?
1
:
0
);
}
static
ssize_t
ps
mouse_attr_set_smartscroll
(
struct
psmouse
*
psmouse
,
const
char
*
buf
,
size_t
count
)
static
ssize_t
ps
2pp_attr_set_smartscroll
(
struct
psmouse
*
psmouse
,
void
*
data
,
const
char
*
buf
,
size_t
count
)
{
unsigned
long
value
;
char
*
rest
;
...
...
@@ -169,7 +169,8 @@ static ssize_t psmouse_attr_set_smartscroll(struct psmouse *psmouse, const char
return
count
;
}
PSMOUSE_DEFINE_ATTR
(
smartscroll
);
PSMOUSE_DEFINE_ATTR
(
smartscroll
,
S_IWUSR
|
S_IRUGO
,
NULL
,
ps2pp_attr_show_smartscroll
,
ps2pp_attr_set_smartscroll
);
/*
* Support 800 dpi resolution _only_ if the user wants it (there are good
...
...
@@ -194,7 +195,7 @@ static void ps2pp_set_resolution(struct psmouse *psmouse, unsigned int resolutio
static
void
ps2pp_disconnect
(
struct
psmouse
*
psmouse
)
{
device_remove_file
(
&
psmouse
->
ps2dev
.
serio
->
dev
,
&
psmouse_attr_smartscroll
);
device_remove_file
(
&
psmouse
->
ps2dev
.
serio
->
dev
,
&
psmouse_attr_smartscroll
.
dattr
);
}
static
struct
ps2pp_info
*
get_model_info
(
unsigned
char
model
)
...
...
@@ -222,6 +223,7 @@ static struct ps2pp_info *get_model_info(unsigned char model)
{
80
,
PS2PP_KIND_WHEEL
,
PS2PP_SIDE_BTN
|
PS2PP_WHEEL
},
{
81
,
PS2PP_KIND_WHEEL
,
PS2PP_WHEEL
},
{
83
,
PS2PP_KIND_WHEEL
,
PS2PP_WHEEL
},
{
86
,
PS2PP_KIND_WHEEL
,
PS2PP_WHEEL
},
{
88
,
PS2PP_KIND_WHEEL
,
PS2PP_WHEEL
},
{
96
,
0
,
0
},
{
97
,
PS2PP_KIND_TP3
,
PS2PP_WHEEL
|
PS2PP_HWHEEL
},
...
...
@@ -379,7 +381,8 @@ int ps2pp_init(struct psmouse *psmouse, int set_properties)
psmouse
->
set_resolution
=
ps2pp_set_resolution
;
psmouse
->
disconnect
=
ps2pp_disconnect
;
device_create_file
(
&
psmouse
->
ps2dev
.
serio
->
dev
,
&
psmouse_attr_smartscroll
);
device_create_file
(
&
psmouse
->
ps2dev
.
serio
->
dev
,
&
psmouse_attr_smartscroll
.
dattr
);
}
}
...
...
drivers/input/mouse/psmouse-base.c
View file @
7f93220b
...
...
@@ -25,6 +25,7 @@
#include "logips2pp.h"
#include "alps.h"
#include "lifebook.h"
#include "trackpoint.h"
#define DRIVER_DESC "PS/2 mouse driver"
...
...
@@ -57,10 +58,30 @@ static unsigned int psmouse_resetafter;
module_param_named
(
resetafter
,
psmouse_resetafter
,
uint
,
0644
);
MODULE_PARM_DESC
(
resetafter
,
"Reset device after so many bad packets (0 = never)."
);
PSMOUSE_DEFINE_ATTR
(
protocol
);
PSMOUSE_DEFINE_ATTR
(
rate
);
PSMOUSE_DEFINE_ATTR
(
resolution
);
PSMOUSE_DEFINE_ATTR
(
resetafter
);
PSMOUSE_DEFINE_ATTR
(
protocol
,
S_IWUSR
|
S_IRUGO
,
NULL
,
psmouse_attr_show_protocol
,
psmouse_attr_set_protocol
);
PSMOUSE_DEFINE_ATTR
(
rate
,
S_IWUSR
|
S_IRUGO
,
(
void
*
)
offsetof
(
struct
psmouse
,
rate
),
psmouse_show_int_attr
,
psmouse_attr_set_rate
);
PSMOUSE_DEFINE_ATTR
(
resolution
,
S_IWUSR
|
S_IRUGO
,
(
void
*
)
offsetof
(
struct
psmouse
,
resolution
),
psmouse_show_int_attr
,
psmouse_attr_set_resolution
);
PSMOUSE_DEFINE_ATTR
(
resetafter
,
S_IWUSR
|
S_IRUGO
,
(
void
*
)
offsetof
(
struct
psmouse
,
resetafter
),
psmouse_show_int_attr
,
psmouse_set_int_attr
);
static
struct
attribute
*
psmouse_attributes
[]
=
{
&
psmouse_attr_protocol
.
dattr
.
attr
,
&
psmouse_attr_rate
.
dattr
.
attr
,
&
psmouse_attr_resolution
.
dattr
.
attr
,
&
psmouse_attr_resetafter
.
dattr
.
attr
,
NULL
};
static
struct
attribute_group
psmouse_attribute_group
=
{
.
attrs
=
psmouse_attributes
,
};
__obsolete_setup
(
"psmouse_noext"
);
__obsolete_setup
(
"psmouse_resolution="
);
...
...
@@ -519,6 +540,12 @@ static int psmouse_extensions(struct psmouse *psmouse,
if
(
max_proto
>=
PSMOUSE_IMPS
&&
intellimouse_detect
(
psmouse
,
set_properties
)
==
0
)
return
PSMOUSE_IMPS
;
/*
* Try to initialize the IBM TrackPoint
*/
if
(
max_proto
>
PSMOUSE_IMEX
&&
trackpoint_detect
(
psmouse
,
set_properties
)
==
0
)
return
PSMOUSE_TRACKPOINT
;
/*
* Okay, all failed, we have a standard mouse here. The number of the buttons
* is still a question, though. We assume 3.
...
...
@@ -599,6 +626,12 @@ static struct psmouse_protocol psmouse_protocols[] = {
.
alias
=
"lifebook"
,
.
init
=
lifebook_init
,
},
{
.
type
=
PSMOUSE_TRACKPOINT
,
.
name
=
"TPPS/2"
,
.
alias
=
"trackpoint"
,
.
detect
=
trackpoint_detect
,
},
{
.
type
=
PSMOUSE_AUTO
,
.
name
=
"auto"
,
...
...
@@ -787,10 +820,7 @@ static void psmouse_disconnect(struct serio *serio)
psmouse
=
serio_get_drvdata
(
serio
);
device_remove_file
(
&
serio
->
dev
,
&
psmouse_attr_protocol
);
device_remove_file
(
&
serio
->
dev
,
&
psmouse_attr_rate
);
device_remove_file
(
&
serio
->
dev
,
&
psmouse_attr_resolution
);
device_remove_file
(
&
serio
->
dev
,
&
psmouse_attr_resetafter
);
sysfs_remove_group
(
&
serio
->
dev
.
kobj
,
&
psmouse_attribute_group
);
down
(
&
psmouse_sem
);
...
...
@@ -927,10 +957,7 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv)
if
(
parent
&&
parent
->
pt_activate
)
parent
->
pt_activate
(
parent
);
device_create_file
(
&
serio
->
dev
,
&
psmouse_attr_protocol
);
device_create_file
(
&
serio
->
dev
,
&
psmouse_attr_rate
);
device_create_file
(
&
serio
->
dev
,
&
psmouse_attr_resolution
);
device_create_file
(
&
serio
->
dev
,
&
psmouse_attr_resetafter
);
sysfs_create_group
(
&
serio
->
dev
.
kobj
,
&
psmouse_attribute_group
);
psmouse_activate
(
psmouse
);
...
...
@@ -1027,10 +1054,12 @@ static struct serio_driver psmouse_drv = {
.
cleanup
=
psmouse_cleanup
,
};
ssize_t
psmouse_attr_show_helper
(
struct
device
*
dev
,
char
*
buf
,
ssize_t
(
*
handler
)(
struct
psmouse
*
,
char
*
)
)
ssize_t
psmouse_attr_show_helper
(
struct
device
*
dev
,
struct
device_attribute
*
devattr
,
char
*
buf
)
{
struct
serio
*
serio
=
to_serio_port
(
dev
);
struct
psmouse_attribute
*
attr
=
to_psmouse_attr
(
devattr
);
struct
psmouse
*
psmouse
;
int
retval
;
retval
=
serio_pin_driver
(
serio
);
...
...
@@ -1042,19 +1071,21 @@ ssize_t psmouse_attr_show_helper(struct device *dev, char *buf,
goto
out
;
}
retval
=
handler
(
serio_get_drvdata
(
serio
),
buf
);
psmouse
=
serio_get_drvdata
(
serio
);
retval
=
attr
->
show
(
psmouse
,
attr
->
data
,
buf
);
out:
serio_unpin_driver
(
serio
);
return
retval
;
}
ssize_t
psmouse_attr_set_helper
(
struct
device
*
dev
,
const
char
*
buf
,
size_t
count
,
ssize_t
(
*
handler
)(
struct
psmouse
*
,
const
char
*
,
size_t
)
)
ssize_t
psmouse_attr_set_helper
(
struct
device
*
dev
,
struct
device_attribute
*
devattr
,
const
char
*
buf
,
size_t
count
)
{
struct
serio
*
serio
=
to_serio_port
(
dev
);
struct
psmouse
*
psmouse
=
serio_get_drvdata
(
serio
);
struct
psmouse
*
parent
=
NULL
;
struct
psmouse
_attribute
*
attr
=
to_psmouse_attr
(
devattr
);
struct
psmouse
*
p
smouse
,
*
p
arent
=
NULL
;
int
retval
;
retval
=
serio_pin_driver
(
serio
);
...
...
@@ -1070,6 +1101,8 @@ ssize_t psmouse_attr_set_helper(struct device *dev, const char *buf, size_t coun
if
(
retval
)
goto
out_unpin
;
psmouse
=
serio_get_drvdata
(
serio
);
if
(
psmouse
->
state
==
PSMOUSE_IGNORE
)
{
retval
=
-
ENODEV
;
goto
out_up
;
...
...
@@ -1082,7 +1115,7 @@ ssize_t psmouse_attr_set_helper(struct device *dev, const char *buf, size_t coun
psmouse_deactivate
(
psmouse
);
retval
=
handler
(
psmouse
,
buf
,
count
);
retval
=
attr
->
set
(
psmouse
,
attr
->
data
,
buf
,
count
);
if
(
retval
!=
-
ENODEV
)
psmouse_activate
(
psmouse
);
...
...
@@ -1097,12 +1130,34 @@ ssize_t psmouse_attr_set_helper(struct device *dev, const char *buf, size_t coun
return
retval
;
}
static
ssize_t
psmouse_attr_show_protocol
(
struct
psmouse
*
psmouse
,
char
*
buf
)
static
ssize_t
psmouse_show_int_attr
(
struct
psmouse
*
psmouse
,
void
*
offset
,
char
*
buf
)
{
unsigned
long
*
field
=
(
unsigned
long
*
)((
char
*
)
psmouse
+
(
size_t
)
offset
);
return
sprintf
(
buf
,
"%lu
\n
"
,
*
field
);
}
static
ssize_t
psmouse_set_int_attr
(
struct
psmouse
*
psmouse
,
void
*
offset
,
const
char
*
buf
,
size_t
count
)
{
unsigned
long
*
field
=
(
unsigned
long
*
)((
char
*
)
psmouse
+
(
size_t
)
offset
);
unsigned
long
value
;
char
*
rest
;
value
=
simple_strtoul
(
buf
,
&
rest
,
10
);
if
(
*
rest
)
return
-
EINVAL
;
*
field
=
value
;
return
count
;
}
static
ssize_t
psmouse_attr_show_protocol
(
struct
psmouse
*
psmouse
,
void
*
data
,
char
*
buf
)
{
return
sprintf
(
buf
,
"%s
\n
"
,
psmouse_protocol_by_type
(
psmouse
->
type
)
->
name
);
}
static
ssize_t
psmouse_attr_set_protocol
(
struct
psmouse
*
psmouse
,
const
char
*
buf
,
size_t
count
)
static
ssize_t
psmouse_attr_set_protocol
(
struct
psmouse
*
psmouse
,
void
*
data
,
const
char
*
buf
,
size_t
count
)
{
struct
serio
*
serio
=
psmouse
->
ps2dev
.
serio
;
struct
psmouse
*
parent
=
NULL
;
...
...
@@ -1166,12 +1221,7 @@ static ssize_t psmouse_attr_set_protocol(struct psmouse *psmouse, const char *bu
return
count
;
}
static
ssize_t
psmouse_attr_show_rate
(
struct
psmouse
*
psmouse
,
char
*
buf
)
{
return
sprintf
(
buf
,
"%d
\n
"
,
psmouse
->
rate
);
}
static
ssize_t
psmouse_attr_set_rate
(
struct
psmouse
*
psmouse
,
const
char
*
buf
,
size_t
count
)
static
ssize_t
psmouse_attr_set_rate
(
struct
psmouse
*
psmouse
,
void
*
data
,
const
char
*
buf
,
size_t
count
)
{
unsigned
long
value
;
char
*
rest
;
...
...
@@ -1184,12 +1234,7 @@ static ssize_t psmouse_attr_set_rate(struct psmouse *psmouse, const char *buf, s
return
count
;
}
static
ssize_t
psmouse_attr_show_resolution
(
struct
psmouse
*
psmouse
,
char
*
buf
)
{
return
sprintf
(
buf
,
"%d
\n
"
,
psmouse
->
resolution
);
}
static
ssize_t
psmouse_attr_set_resolution
(
struct
psmouse
*
psmouse
,
const
char
*
buf
,
size_t
count
)
static
ssize_t
psmouse_attr_set_resolution
(
struct
psmouse
*
psmouse
,
void
*
data
,
const
char
*
buf
,
size_t
count
)
{
unsigned
long
value
;
char
*
rest
;
...
...
@@ -1202,23 +1247,6 @@ static ssize_t psmouse_attr_set_resolution(struct psmouse *psmouse, const char *
return
count
;
}
static
ssize_t
psmouse_attr_show_resetafter
(
struct
psmouse
*
psmouse
,
char
*
buf
)
{
return
sprintf
(
buf
,
"%d
\n
"
,
psmouse
->
resetafter
);
}
static
ssize_t
psmouse_attr_set_resetafter
(
struct
psmouse
*
psmouse
,
const
char
*
buf
,
size_t
count
)
{
unsigned
long
value
;
char
*
rest
;
value
=
simple_strtoul
(
buf
,
&
rest
,
10
);
if
(
*
rest
)
return
-
EINVAL
;
psmouse
->
resetafter
=
value
;
return
count
;
}
static
int
psmouse_set_maxproto
(
const
char
*
val
,
struct
kernel_param
*
kp
)
{
...
...
@@ -1234,7 +1262,7 @@ static int psmouse_set_maxproto(const char *val, struct kernel_param *kp)
*
((
unsigned
int
*
)
kp
->
arg
)
=
proto
->
type
;
return
0
;
\
return
0
;
}
static
int
psmouse_get_maxproto
(
char
*
buffer
,
struct
kernel_param
*
kp
)
...
...
drivers/input/mouse/psmouse.h
View file @
7f93220b
...
...
@@ -78,6 +78,7 @@ enum psmouse_type {
PSMOUSE_SYNAPTICS
,
PSMOUSE_ALPS
,
PSMOUSE_LIFEBOOK
,
PSMOUSE_TRACKPOINT
,
PSMOUSE_AUTO
/* This one should always be last */
};
...
...
@@ -85,24 +86,37 @@ int psmouse_sliced_command(struct psmouse *psmouse, unsigned char command);
int
psmouse_reset
(
struct
psmouse
*
psmouse
);
void
psmouse_set_resolution
(
struct
psmouse
*
psmouse
,
unsigned
int
resolution
);
ssize_t
psmouse_attr_show_helper
(
struct
device
*
dev
,
char
*
buf
,
ssize_t
(
*
handler
)(
struct
psmouse
*
,
char
*
));
ssize_t
psmouse_attr_set_helper
(
struct
device
*
dev
,
const
char
*
buf
,
size_t
count
,
ssize_t
(
*
handler
)(
struct
psmouse
*
,
const
char
*
,
size_t
));
#define PSMOUSE_DEFINE_ATTR(_name) \
static ssize_t psmouse_attr_show_##_name(struct psmouse *, char *); \
static ssize_t psmouse_attr_set_##_name(struct psmouse *, const char *, size_t);\
static ssize_t psmouse_do_show_##_name(struct device *d, struct device_attribute *attr, char *b) \
{ \
return psmouse_attr_show_helper(d, b, psmouse_attr_show_##_name); \
} \
static ssize_t psmouse_do_set_##_name(struct device *d, struct device_attribute *attr, const char *b, size_t s)\
{ \
return psmouse_attr_set_helper(d, b, s, psmouse_attr_set_##_name); \
} \
static struct device_attribute psmouse_attr_##_name = \
__ATTR(_name, S_IWUSR | S_IRUGO, \
psmouse_do_show_##_name, psmouse_do_set_##_name);
struct
psmouse_attribute
{
struct
device_attribute
dattr
;
void
*
data
;
ssize_t
(
*
show
)(
struct
psmouse
*
psmouse
,
void
*
data
,
char
*
buf
);
ssize_t
(
*
set
)(
struct
psmouse
*
psmouse
,
void
*
data
,
const
char
*
buf
,
size_t
count
);
};
#define to_psmouse_attr(a) container_of((a), struct psmouse_attribute, dattr)
ssize_t
psmouse_attr_show_helper
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
char
*
buf
);
ssize_t
psmouse_attr_set_helper
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
const
char
*
buf
,
size_t
count
);
#define PSMOUSE_DEFINE_ATTR(_name, _mode, _data, _show, _set) \
static ssize_t _show(struct psmouse *, void *data, char *); \
static ssize_t _set(struct psmouse *, void *data, const char *, size_t); \
static struct psmouse_attribute psmouse_attr_##_name = { \
.dattr = { \
.attr = { \
.name = __stringify(_name), \
.mode = _mode, \
.owner = THIS_MODULE, \
}, \
.show = psmouse_attr_show_helper, \
.store = psmouse_attr_set_helper, \
}, \
.data = _data, \
.show = _show, \
.set = _set, \
}
#endif
/* _PSMOUSE_H */
drivers/input/mouse/trackpoint.c
0 → 100644
View file @
7f93220b
/*
* Stephen Evanchik <evanchsa@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.
*
* Trademarks are the property of their respective owners.
*/
#include <linux/delay.h>
#include <linux/serio.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/input.h>
#include <linux/libps2.h>
#include <linux/proc_fs.h>
#include <asm/uaccess.h>
#include "psmouse.h"
#include "trackpoint.h"
/*
* Device IO: read, write and toggle bit
*/
static
int
trackpoint_read
(
struct
ps2dev
*
ps2dev
,
unsigned
char
loc
,
unsigned
char
*
results
)
{
if
(
ps2_command
(
ps2dev
,
NULL
,
MAKE_PS2_CMD
(
0
,
0
,
TP_COMMAND
))
||
ps2_command
(
ps2dev
,
results
,
MAKE_PS2_CMD
(
0
,
1
,
loc
)))
{
return
-
1
;
}
return
0
;
}
static
int
trackpoint_write
(
struct
ps2dev
*
ps2dev
,
unsigned
char
loc
,
unsigned
char
val
)
{
if
(
ps2_command
(
ps2dev
,
NULL
,
MAKE_PS2_CMD
(
0
,
0
,
TP_COMMAND
))
||
ps2_command
(
ps2dev
,
NULL
,
MAKE_PS2_CMD
(
0
,
0
,
TP_WRITE_MEM
))
||
ps2_command
(
ps2dev
,
NULL
,
MAKE_PS2_CMD
(
0
,
0
,
loc
))
||
ps2_command
(
ps2dev
,
NULL
,
MAKE_PS2_CMD
(
0
,
0
,
val
)))
{
return
-
1
;
}
return
0
;
}
static
int
trackpoint_toggle_bit
(
struct
ps2dev
*
ps2dev
,
unsigned
char
loc
,
unsigned
char
mask
)
{
/* Bad things will happen if the loc param isn't in this range */
if
(
loc
<
0x20
||
loc
>=
0x2F
)
return
-
1
;
if
(
ps2_command
(
ps2dev
,
NULL
,
MAKE_PS2_CMD
(
0
,
0
,
TP_COMMAND
))
||
ps2_command
(
ps2dev
,
NULL
,
MAKE_PS2_CMD
(
0
,
0
,
TP_TOGGLE
))
||
ps2_command
(
ps2dev
,
NULL
,
MAKE_PS2_CMD
(
0
,
0
,
loc
))
||
ps2_command
(
ps2dev
,
NULL
,
MAKE_PS2_CMD
(
0
,
0
,
mask
)))
{
return
-
1
;
}
return
0
;
}
/*
* Trackpoint-specific attributes
*/
struct
trackpoint_attr_data
{
size_t
field_offset
;
unsigned
char
command
;
unsigned
char
mask
;
};
static
ssize_t
trackpoint_show_int_attr
(
struct
psmouse
*
psmouse
,
void
*
data
,
char
*
buf
)
{
struct
trackpoint_data
*
tp
=
psmouse
->
private
;
struct
trackpoint_attr_data
*
attr
=
data
;
unsigned
char
*
field
=
(
unsigned
char
*
)((
char
*
)
tp
+
attr
->
field_offset
);
return
sprintf
(
buf
,
"%u
\n
"
,
*
field
);
}
static
ssize_t
trackpoint_set_int_attr
(
struct
psmouse
*
psmouse
,
void
*
data
,
const
char
*
buf
,
size_t
count
)
{
struct
trackpoint_data
*
tp
=
psmouse
->
private
;
struct
trackpoint_attr_data
*
attr
=
data
;
unsigned
char
*
field
=
(
unsigned
char
*
)((
char
*
)
tp
+
attr
->
field_offset
);
unsigned
long
value
;
char
*
rest
;
value
=
simple_strtoul
(
buf
,
&
rest
,
10
);
if
(
*
rest
||
value
>
255
)
return
-
EINVAL
;
*
field
=
value
;
trackpoint_write
(
&
psmouse
->
ps2dev
,
attr
->
command
,
value
);
return
count
;
}
#define TRACKPOINT_INT_ATTR(_name, _command) \
static struct trackpoint_attr_data trackpoint_attr_##_name = { \
.field_offset = offsetof(struct trackpoint_data, _name), \
.command = _command, \
}; \
PSMOUSE_DEFINE_ATTR(_name, S_IWUSR | S_IRUGO, \
&trackpoint_attr_##_name, \
trackpoint_show_int_attr, trackpoint_set_int_attr)
static
ssize_t
trackpoint_set_bit_attr
(
struct
psmouse
*
psmouse
,
void
*
data
,
const
char
*
buf
,
size_t
count
)
{
struct
trackpoint_data
*
tp
=
psmouse
->
private
;
struct
trackpoint_attr_data
*
attr
=
data
;
unsigned
char
*
field
=
(
unsigned
char
*
)((
char
*
)
tp
+
attr
->
field_offset
);
unsigned
long
value
;
char
*
rest
;
value
=
simple_strtoul
(
buf
,
&
rest
,
10
);
if
(
*
rest
||
value
>
1
)
return
-
EINVAL
;
if
(
*
field
!=
value
)
{
*
field
=
value
;
trackpoint_toggle_bit
(
&
psmouse
->
ps2dev
,
attr
->
command
,
attr
->
mask
);
}
return
count
;
}
#define TRACKPOINT_BIT_ATTR(_name, _command, _mask) \
static struct trackpoint_attr_data trackpoint_attr_##_name = { \
.field_offset = offsetof(struct trackpoint_data, _name), \
.command = _command, \
.mask = _mask, \
}; \
PSMOUSE_DEFINE_ATTR(_name, S_IWUSR | S_IRUGO, \
&trackpoint_attr_##_name, \
trackpoint_show_int_attr, trackpoint_set_bit_attr)
TRACKPOINT_INT_ATTR
(
sensitivity
,
TP_SENS
);
TRACKPOINT_INT_ATTR
(
speed
,
TP_SPEED
);
TRACKPOINT_INT_ATTR
(
inertia
,
TP_INERTIA
);
TRACKPOINT_INT_ATTR
(
reach
,
TP_REACH
);
TRACKPOINT_INT_ATTR
(
draghys
,
TP_DRAGHYS
);
TRACKPOINT_INT_ATTR
(
mindrag
,
TP_MINDRAG
);
TRACKPOINT_INT_ATTR
(
thresh
,
TP_THRESH
);
TRACKPOINT_INT_ATTR
(
upthresh
,
TP_UP_THRESH
);
TRACKPOINT_INT_ATTR
(
ztime
,
TP_Z_TIME
);
TRACKPOINT_INT_ATTR
(
jenks
,
TP_JENKS_CURV
);
TRACKPOINT_BIT_ATTR
(
press_to_select
,
TP_TOGGLE_PTSON
,
TP_MASK_PTSON
);
TRACKPOINT_BIT_ATTR
(
skipback
,
TP_TOGGLE_SKIPBACK
,
TP_MASK_SKIPBACK
);
TRACKPOINT_BIT_ATTR
(
ext_dev
,
TP_TOGGLE_EXT_DEV
,
TP_MASK_EXT_DEV
);
static
struct
attribute
*
trackpoint_attrs
[]
=
{
&
psmouse_attr_sensitivity
.
dattr
.
attr
,
&
psmouse_attr_speed
.
dattr
.
attr
,
&
psmouse_attr_inertia
.
dattr
.
attr
,
&
psmouse_attr_reach
.
dattr
.
attr
,
&
psmouse_attr_draghys
.
dattr
.
attr
,
&
psmouse_attr_mindrag
.
dattr
.
attr
,
&
psmouse_attr_thresh
.
dattr
.
attr
,
&
psmouse_attr_upthresh
.
dattr
.
attr
,
&
psmouse_attr_ztime
.
dattr
.
attr
,
&
psmouse_attr_jenks
.
dattr
.
attr
,
&
psmouse_attr_press_to_select
.
dattr
.
attr
,
&
psmouse_attr_skipback
.
dattr
.
attr
,
&
psmouse_attr_ext_dev
.
dattr
.
attr
,
NULL
};
static
struct
attribute_group
trackpoint_attr_group
=
{
.
attrs
=
trackpoint_attrs
,
};
static
void
trackpoint_disconnect
(
struct
psmouse
*
psmouse
)
{
sysfs_remove_group
(
&
psmouse
->
ps2dev
.
serio
->
dev
.
kobj
,
&
trackpoint_attr_group
);
kfree
(
psmouse
->
private
);
psmouse
->
private
=
NULL
;
}
static
int
trackpoint_sync
(
struct
psmouse
*
psmouse
)
{
unsigned
char
toggle
;
struct
trackpoint_data
*
tp
=
psmouse
->
private
;
if
(
!
tp
)
return
-
1
;
/* Disable features that may make device unusable with this driver */
trackpoint_read
(
&
psmouse
->
ps2dev
,
TP_TOGGLE_TWOHAND
,
&
toggle
);
if
(
toggle
&
TP_MASK_TWOHAND
)
trackpoint_toggle_bit
(
&
psmouse
->
ps2dev
,
TP_TOGGLE_TWOHAND
,
TP_MASK_TWOHAND
);
trackpoint_read
(
&
psmouse
->
ps2dev
,
TP_TOGGLE_SOURCE_TAG
,
&
toggle
);
if
(
toggle
&
TP_MASK_SOURCE_TAG
)
trackpoint_toggle_bit
(
&
psmouse
->
ps2dev
,
TP_TOGGLE_SOURCE_TAG
,
TP_MASK_SOURCE_TAG
);
trackpoint_read
(
&
psmouse
->
ps2dev
,
TP_TOGGLE_MB
,
&
toggle
);
if
(
toggle
&
TP_MASK_MB
)
trackpoint_toggle_bit
(
&
psmouse
->
ps2dev
,
TP_TOGGLE_MB
,
TP_MASK_MB
);
/* Push the config to the device */
trackpoint_write
(
&
psmouse
->
ps2dev
,
TP_SENS
,
tp
->
sensitivity
);
trackpoint_write
(
&
psmouse
->
ps2dev
,
TP_INERTIA
,
tp
->
inertia
);
trackpoint_write
(
&
psmouse
->
ps2dev
,
TP_SPEED
,
tp
->
speed
);
trackpoint_write
(
&
psmouse
->
ps2dev
,
TP_REACH
,
tp
->
reach
);
trackpoint_write
(
&
psmouse
->
ps2dev
,
TP_DRAGHYS
,
tp
->
draghys
);
trackpoint_write
(
&
psmouse
->
ps2dev
,
TP_MINDRAG
,
tp
->
mindrag
);
trackpoint_write
(
&
psmouse
->
ps2dev
,
TP_THRESH
,
tp
->
thresh
);
trackpoint_write
(
&
psmouse
->
ps2dev
,
TP_UP_THRESH
,
tp
->
upthresh
);
trackpoint_write
(
&
psmouse
->
ps2dev
,
TP_Z_TIME
,
tp
->
ztime
);
trackpoint_write
(
&
psmouse
->
ps2dev
,
TP_JENKS_CURV
,
tp
->
jenks
);
trackpoint_read
(
&
psmouse
->
ps2dev
,
TP_TOGGLE_PTSON
,
&
toggle
);
if
(((
toggle
&
TP_MASK_PTSON
)
==
TP_MASK_PTSON
)
!=
tp
->
press_to_select
)
trackpoint_toggle_bit
(
&
psmouse
->
ps2dev
,
TP_TOGGLE_PTSON
,
TP_MASK_PTSON
);
trackpoint_read
(
&
psmouse
->
ps2dev
,
TP_TOGGLE_SKIPBACK
,
&
toggle
);
if
(((
toggle
&
TP_MASK_SKIPBACK
)
==
TP_MASK_SKIPBACK
)
!=
tp
->
skipback
)
trackpoint_toggle_bit
(
&
psmouse
->
ps2dev
,
TP_TOGGLE_SKIPBACK
,
TP_MASK_SKIPBACK
);
trackpoint_read
(
&
psmouse
->
ps2dev
,
TP_TOGGLE_EXT_DEV
,
&
toggle
);
if
(((
toggle
&
TP_MASK_EXT_DEV
)
==
TP_MASK_EXT_DEV
)
!=
tp
->
ext_dev
)
trackpoint_toggle_bit
(
&
psmouse
->
ps2dev
,
TP_TOGGLE_EXT_DEV
,
TP_MASK_EXT_DEV
);
return
0
;
}
static
void
trackpoint_defaults
(
struct
trackpoint_data
*
tp
)
{
tp
->
press_to_select
=
TP_DEF_PTSON
;
tp
->
sensitivity
=
TP_DEF_SENS
;
tp
->
speed
=
TP_DEF_SPEED
;
tp
->
reach
=
TP_DEF_REACH
;
tp
->
draghys
=
TP_DEF_DRAGHYS
;
tp
->
mindrag
=
TP_DEF_MINDRAG
;
tp
->
thresh
=
TP_DEF_THRESH
;
tp
->
upthresh
=
TP_DEF_UP_THRESH
;
tp
->
ztime
=
TP_DEF_Z_TIME
;
tp
->
jenks
=
TP_DEF_JENKS_CURV
;
tp
->
inertia
=
TP_DEF_INERTIA
;
tp
->
skipback
=
TP_DEF_SKIPBACK
;
tp
->
ext_dev
=
TP_DEF_EXT_DEV
;
}
int
trackpoint_detect
(
struct
psmouse
*
psmouse
,
int
set_properties
)
{
struct
trackpoint_data
*
priv
;
struct
ps2dev
*
ps2dev
=
&
psmouse
->
ps2dev
;
unsigned
char
firmware_id
;
unsigned
char
button_info
;
unsigned
char
param
[
2
];
param
[
0
]
=
param
[
1
]
=
0
;
if
(
ps2_command
(
ps2dev
,
param
,
MAKE_PS2_CMD
(
0
,
2
,
TP_READ_ID
)))
return
-
1
;
if
(
param
[
0
]
!=
TP_MAGIC_IDENT
)
return
-
1
;
if
(
!
set_properties
)
return
0
;
firmware_id
=
param
[
1
];
if
(
trackpoint_read
(
&
psmouse
->
ps2dev
,
TP_EXT_BTN
,
&
button_info
))
{
printk
(
KERN_WARNING
"trackpoint.c: failed to get extended button data
\n
"
);
button_info
=
0
;
}
psmouse
->
private
=
priv
=
kcalloc
(
1
,
sizeof
(
struct
trackpoint_data
),
GFP_KERNEL
);
if
(
!
priv
)
return
-
1
;
psmouse
->
vendor
=
"IBM"
;
psmouse
->
name
=
"TrackPoint"
;
psmouse
->
reconnect
=
trackpoint_sync
;
psmouse
->
disconnect
=
trackpoint_disconnect
;
trackpoint_defaults
(
priv
);
trackpoint_sync
(
psmouse
);
sysfs_create_group
(
&
ps2dev
->
serio
->
dev
.
kobj
,
&
trackpoint_attr_group
);
printk
(
KERN_INFO
"IBM TrackPoint firmware: 0x%02x, buttons: %d/%d
\n
"
,
firmware_id
,
(
button_info
&
0xf0
)
>>
4
,
button_info
&
0x0f
);
return
0
;
}
drivers/input/mouse/trackpoint.h
0 → 100644
View file @
7f93220b
/*
* IBM TrackPoint PS/2 mouse driver
*
* Stephen Evanchik <evanchsa@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.
*/
#ifndef _TRACKPOINT_H
#define _TRACKPOINT_H
/*
* These constants are from the TrackPoint System
* Engineering documentation Version 4 from IBM Watson
* research:
* http://wwwcssrv.almaden.ibm.com/trackpoint/download.html
*/
#define TP_COMMAND 0xE2
/* Commands start with this */
#define TP_READ_ID 0xE1
/* Sent for device identification */
#define TP_MAGIC_IDENT 0x01
/* Sent after a TP_READ_ID followed */
/* by the firmware ID */
/*
* Commands
*/
#define TP_RECALIB 0x51
/* Recalibrate */
#define TP_POWER_DOWN 0x44
/* Can only be undone through HW reset */
#define TP_EXT_DEV 0x21
/* Determines if external device is connected (RO) */
#define TP_EXT_BTN 0x4B
/* Read extended button status */
#define TP_POR 0x7F
/* Execute Power on Reset */
#define TP_POR_RESULTS 0x25
/* Read Power on Self test results */
#define TP_DISABLE_EXT 0x40
/* Disable external pointing device */
#define TP_ENABLE_EXT 0x41
/* Enable external pointing device */
/*
* Mode manipulation
*/
#define TP_SET_SOFT_TRANS 0x4E
/* Set mode */
#define TP_CANCEL_SOFT_TRANS 0xB9
/* Cancel mode */
#define TP_SET_HARD_TRANS 0x45
/* Mode can only be set */
/*
* Register oriented commands/properties
*/
#define TP_WRITE_MEM 0x81
#define TP_READ_MEM 0x80
/* Not used in this implementation */
/*
* RAM Locations for properties
*/
#define TP_SENS 0x4A
/* Sensitivity */
#define TP_MB 0x4C
/* Read Middle Button Status (RO) */
#define TP_INERTIA 0x4D
/* Negative Inertia */
#define TP_SPEED 0x60
/* Speed of TP Cursor */
#define TP_REACH 0x57
/* Backup for Z-axis press */
#define TP_DRAGHYS 0x58
/* Drag Hysteresis */
/* (how hard it is to drag */
/* with Z-axis pressed) */
#define TP_MINDRAG 0x59
/* Minimum amount of force needed */
/* to trigger dragging */
#define TP_THRESH 0x5C
/* Minimum value for a Z-axis press */
#define TP_UP_THRESH 0x5A
/* Used to generate a 'click' on Z-axis */
#define TP_Z_TIME 0x5E
/* How sharp of a press */
#define TP_JENKS_CURV 0x5D
/* Minimum curvature for double click */
/*
* Toggling Flag bits
*/
#define TP_TOGGLE 0x47
/* Toggle command */
#define TP_TOGGLE_MB 0x23
/* Disable/Enable Middle Button */
#define TP_MASK_MB 0x01
#define TP_TOGGLE_EXT_DEV 0x23
/* Toggle external device */
#define TP_MASK_EXT_DEV 0x02
#define TP_TOGGLE_DRIFT 0x23
/* Drift Correction */
#define TP_MASK_DRIFT 0x80
#define TP_TOGGLE_BURST 0x28
/* Burst Mode */
#define TP_MASK_BURST 0x80
#define TP_TOGGLE_PTSON 0x2C
/* Press to Select */
#define TP_MASK_PTSON 0x01
#define TP_TOGGLE_HARD_TRANS 0x2C
/* Alternate method to set Hard Transparency */
#define TP_MASK_HARD_TRANS 0x80
#define TP_TOGGLE_TWOHAND 0x2D
/* Two handed */
#define TP_MASK_TWOHAND 0x01
#define TP_TOGGLE_STICKY_TWO 0x2D
/* Sticky two handed */
#define TP_MASK_STICKY_TWO 0x04
#define TP_TOGGLE_SKIPBACK 0x2D
/* Suppress movement after drag release */
#define TP_MASK_SKIPBACK 0x08
#define TP_TOGGLE_SOURCE_TAG 0x20
/* Bit 3 of the first packet will be set to
to the origin of the packet (external or TP) */
#define TP_MASK_SOURCE_TAG 0x80
#define TP_TOGGLE_EXT_TAG 0x22
/* Bit 3 of the first packet coming from the
external device will be forced to 1 */
#define TP_MASK_EXT_TAG 0x04
/* Power on Self Test Results */
#define TP_POR_SUCCESS 0x3B
/*
* Default power on values
*/
#define TP_DEF_SENS 0x80
#define TP_DEF_INERTIA 0x06
#define TP_DEF_SPEED 0x61
#define TP_DEF_REACH 0x0A
#define TP_DEF_DRAGHYS 0xFF
#define TP_DEF_MINDRAG 0x14
#define TP_DEF_THRESH 0x08
#define TP_DEF_UP_THRESH 0xFF
#define TP_DEF_Z_TIME 0x26
#define TP_DEF_JENKS_CURV 0x87
/* Toggles */
#define TP_DEF_MB 0x00
#define TP_DEF_PTSON 0x00
#define TP_DEF_SKIPBACK 0x00
#define TP_DEF_EXT_DEV 0x01
#define MAKE_PS2_CMD(params, results, cmd) ((params<<12) | (results<<8) | (cmd))
struct
trackpoint_data
{
unsigned
char
sensitivity
,
speed
,
inertia
,
reach
;
unsigned
char
draghys
,
mindrag
;
unsigned
char
thresh
,
upthresh
;
unsigned
char
ztime
,
jenks
;
unsigned
char
press_to_select
;
unsigned
char
skipback
;
unsigned
char
ext_dev
;
};
extern
int
trackpoint_detect
(
struct
psmouse
*
psmouse
,
int
set_properties
);
#endif
/* _TRACKPOINT_H */
drivers/input/serio/i8042-io.h
View file @
7f93220b
...
...
@@ -69,16 +69,16 @@ static inline int i8042_platform_init(void)
*/
#if !defined(__sh__) && !defined(__alpha__) && !defined(__mips__) && !defined(CONFIG_PPC64)
if
(
!
request_region
(
I8042_DATA_REG
,
16
,
"i8042"
))
return
-
1
;
return
-
EBUSY
;
#endif
i8042_reset
=
1
;
#if defined(CONFIG_PPC64)
if
(
check_legacy_ioport
(
I8042_DATA_REG
))
return
-
1
;
return
-
EBUSY
;
if
(
!
request_region
(
I8042_DATA_REG
,
16
,
"i8042"
))
return
-
1
;
return
-
EBUSY
;
#endif
return
0
;
}
...
...
drivers/input/serio/i8042-ip22io.h
View file @
7f93220b
...
...
@@ -58,7 +58,7 @@ static inline int i8042_platform_init(void)
#if 0
/* XXX sgi_kh is a virtual address */
if (!request_mem_region(sgi_kh, sizeof(struct hpc_keyb), "i8042"))
return
1
;
return
-EBUSY
;
#endif
i8042_reset
=
1
;
...
...
drivers/input/serio/i8042-jazzio.h
View file @
7f93220b
...
...
@@ -53,7 +53,7 @@ static inline int i8042_platform_init(void)
#if 0
/* XXX JAZZ_KEYBOARD_ADDRESS is a virtual address */
if (!request_mem_region(JAZZ_KEYBOARD_ADDRESS, 2, "i8042"))
return
1
;
return
-EBUSY
;
#endif
return
0
;
...
...
drivers/input/serio/i8042-sparcio.h
View file @
7f93220b
...
...
@@ -48,10 +48,10 @@ static inline void i8042_write_command(int val)
#define OBP_PS2MS_NAME1 "kdmouse"
#define OBP_PS2MS_NAME2 "mouse"
static
int
i8042_platform_init
(
void
)
static
int
__init
i8042_platform_init
(
void
)
{
#ifndef CONFIG_PCI
return
-
1
;
return
-
ENODEV
;
#else
char
prop
[
128
];
int
len
;
...
...
@@ -59,14 +59,14 @@ static int i8042_platform_init(void)
len
=
prom_getproperty
(
prom_root_node
,
"name"
,
prop
,
sizeof
(
prop
));
if
(
len
<
0
)
{
printk
(
"i8042: Cannot get name property of root OBP node.
\n
"
);
return
-
1
;
return
-
ENODEV
;
}
if
(
strncmp
(
prop
,
"SUNW,JavaStation-1"
,
len
)
==
0
)
{
/* Hardcoded values for MrCoffee. */
i8042_kbd_irq
=
i8042_aux_irq
=
13
|
0x20
;
kbd_iobase
=
ioremap
(
0x71300060
,
8
);
if
(
!
kbd_iobase
)
return
-
1
;
return
-
ENODEV
;
}
else
{
struct
linux_ebus
*
ebus
;
struct
linux_ebus_device
*
edev
;
...
...
@@ -78,7 +78,7 @@ static int i8042_platform_init(void)
goto
edev_found
;
}
}
return
-
1
;
return
-
ENODEV
;
edev_found:
for_each_edevchild
(
edev
,
child
)
{
...
...
@@ -96,7 +96,7 @@ static int i8042_platform_init(void)
i8042_aux_irq
==
-
1
)
{
printk
(
"i8042: Error, 8042 device lacks both kbd and "
"mouse nodes.
\n
"
);
return
-
1
;
return
-
ENODEV
;
}
}
...
...
drivers/input/serio/i8042-x86ia64io.h
View file @
7f93220b
...
...
@@ -137,6 +137,13 @@ static struct dmi_system_id __initdata i8042_dmi_nomux_table[] = {
DMI_MATCH
(
DMI_PRODUCT_NAME
,
"LIFEBOOK T3010"
),
},
},
{
.
ident
=
"Fujitsu-Siemens Lifebook E4010"
,
.
matches
=
{
DMI_MATCH
(
DMI_SYS_VENDOR
,
"FUJITSU SIEMENS"
),
DMI_MATCH
(
DMI_PRODUCT_NAME
,
"LIFEBOOK E4010"
),
},
},
{
.
ident
=
"Toshiba P10"
,
.
matches
=
{
...
...
@@ -256,9 +263,10 @@ static void i8042_pnp_exit(void)
}
}
static
int
i8042_pnp_init
(
void
)
static
int
__init
i8042_pnp_init
(
void
)
{
int
result_kbd
,
result_aux
;
int
result_kbd
=
0
,
result_aux
=
0
;
char
kbd_irq_str
[
4
]
=
{
0
},
aux_irq_str
[
4
]
=
{
0
};
if
(
i8042_nopnp
)
{
printk
(
KERN_INFO
"i8042: PNP detection disabled
\n
"
);
...
...
@@ -267,6 +275,7 @@ static int i8042_pnp_init(void)
if
((
result_kbd
=
pnp_register_driver
(
&
i8042_pnp_kbd_driver
))
>=
0
)
i8042_pnp_kbd_registered
=
1
;
if
((
result_aux
=
pnp_register_driver
(
&
i8042_pnp_aux_driver
))
>=
0
)
i8042_pnp_aux_registered
=
1
;
...
...
@@ -280,6 +289,27 @@ static int i8042_pnp_init(void)
#endif
}
if
(
result_kbd
>
0
)
snprintf
(
kbd_irq_str
,
sizeof
(
kbd_irq_str
),
"%d"
,
i8042_pnp_kbd_irq
);
if
(
result_aux
>
0
)
snprintf
(
aux_irq_str
,
sizeof
(
aux_irq_str
),
"%d"
,
i8042_pnp_aux_irq
);
printk
(
KERN_INFO
"PNP: PS/2 Controller [%s%s%s] at %#x,%#x irq %s%s%s
\n
"
,
i8042_pnp_kbd_name
,
(
result_kbd
>
0
&&
result_aux
>
0
)
?
","
:
""
,
i8042_pnp_aux_name
,
i8042_pnp_data_reg
,
i8042_pnp_command_reg
,
kbd_irq_str
,
(
result_kbd
>
0
&&
result_aux
>
0
)
?
","
:
""
,
aux_irq_str
);
#if defined(__ia64__)
if
(
result_kbd
<=
0
)
i8042_nokbd
=
1
;
if
(
result_aux
<=
0
)
i8042_noaux
=
1
;
#endif
if
(((
i8042_pnp_data_reg
&
~
0xf
)
==
(
i8042_data_reg
&
~
0xf
)
&&
i8042_pnp_data_reg
!=
i8042_data_reg
)
||
!
i8042_pnp_data_reg
)
{
printk
(
KERN_WARNING
"PNP: PS/2 controller has invalid data port %#x; using default %#x
\n
"
,
...
...
@@ -294,53 +324,47 @@ static int i8042_pnp_init(void)
i8042_pnp_command_reg
=
i8042_command_reg
;
}
if
(
!
i8042_pnp_kbd_irq
)
{
printk
(
KERN_WARNING
"PNP: PS/2 controller doesn't have KBD irq; using default %
#x
\n
"
,
i8042_kbd_irq
);
if
(
!
i8042_
nokbd
&&
!
i8042_
pnp_kbd_irq
)
{
printk
(
KERN_WARNING
"PNP: PS/2 controller doesn't have KBD irq; using default %
d
\n
"
,
i8042_kbd_irq
);
i8042_pnp_kbd_irq
=
i8042_kbd_irq
;
}
if
(
!
i8042_pnp_aux_irq
)
{
printk
(
KERN_WARNING
"PNP: PS/2 controller doesn't have AUX irq; using default %
#x
\n
"
,
i8042_aux_irq
);
if
(
!
i8042_
noaux
&&
!
i8042_
pnp_aux_irq
)
{
printk
(
KERN_WARNING
"PNP: PS/2 controller doesn't have AUX irq; using default %
d
\n
"
,
i8042_aux_irq
);
i8042_pnp_aux_irq
=
i8042_aux_irq
;
}
#if defined(__ia64__)
if
(
result_aux
<=
0
)
i8042_noaux
=
1
;
#endif
i8042_data_reg
=
i8042_pnp_data_reg
;
i8042_command_reg
=
i8042_pnp_command_reg
;
i8042_kbd_irq
=
i8042_pnp_kbd_irq
;
i8042_aux_irq
=
i8042_pnp_aux_irq
;
printk
(
KERN_INFO
"PNP: PS/2 Controller [%s%s%s] at %#x,%#x irq %d%s%d
\n
"
,
i8042_pnp_kbd_name
,
(
result_kbd
>
0
&&
result_aux
>
0
)
?
","
:
""
,
i8042_pnp_aux_name
,
i8042_data_reg
,
i8042_command_reg
,
i8042_kbd_irq
,
(
result_aux
>
0
)
?
","
:
""
,
i8042_aux_irq
);
return
0
;
}
#else
static
inline
int
i8042_pnp_init
(
void
)
{
return
0
;
}
static
inline
void
i8042_pnp_exit
(
void
)
{
}
#endif
static
in
line
in
t
i8042_platform_init
(
void
)
static
in
t
__ini
t
i8042_platform_init
(
void
)
{
int
retval
;
/*
* On ix86 platforms touching the i8042 data register region can do really
* bad things. Because of this the region is always reserved on ix86 boxes.
*
* if (!request_region(I8042_DATA_REG, 16, "i8042"))
* return -
1
;
* return -
EBUSY
;
*/
i8042_kbd_irq
=
I8042_MAP_IRQ
(
1
);
i8042_aux_irq
=
I8042_MAP_IRQ
(
12
);
#ifdef CONFIG_PNP
if
(
i8042_pnp_init
())
return
-
1
;
#endif
retval
=
i8042_pnp_init
();
if
(
retval
)
return
retval
;
#if defined(__ia64__)
i8042_reset
=
1
;
...
...
@@ -354,14 +378,12 @@ static inline int i8042_platform_init(void)
i8042_nomux
=
1
;
#endif
return
0
;
return
retval
;
}
static
inline
void
i8042_platform_exit
(
void
)
{
#ifdef CONFIG_PNP
i8042_pnp_exit
();
#endif
}
#endif
/* _I8042_X86IA64IO_H */
drivers/input/serio/i8042.c
View file @
7f93220b
...
...
@@ -27,6 +27,10 @@ MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
MODULE_DESCRIPTION
(
"i8042 keyboard and mouse controller driver"
);
MODULE_LICENSE
(
"GPL"
);
static
unsigned
int
i8042_nokbd
;
module_param_named
(
nokbd
,
i8042_nokbd
,
bool
,
0
);
MODULE_PARM_DESC
(
nokbd
,
"Do not probe or use KBD port."
);
static
unsigned
int
i8042_noaux
;
module_param_named
(
noaux
,
i8042_noaux
,
bool
,
0
);
MODULE_PARM_DESC
(
noaux
,
"Do not probe or use AUX (mouse) port."
);
...
...
@@ -338,10 +342,10 @@ static int i8042_open(struct serio *serio)
return
0
;
activate_fail:
activate_fail:
free_irq
(
port
->
irq
,
i8042_request_irq_cookie
);
irq_fail:
irq_fail:
serio_unregister_port_delayed
(
serio
);
return
-
1
;
...
...
@@ -485,7 +489,7 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id, struct pt_regs *regs)
serio_interrupt
(
port
->
serio
,
data
,
dfl
,
regs
);
ret
=
1
;
out:
out:
return
IRQ_RETVAL
(
ret
);
}
...
...
@@ -552,7 +556,7 @@ static int i8042_enable_mux_ports(void)
* Enable all muxed ports.
*/
for
(
i
=
0
;
i
<
4
;
i
++
)
{
for
(
i
=
0
;
i
<
I8042_NUM_MUX_PORTS
;
i
++
)
{
i8042_command
(
&
param
,
I8042_CMD_MUX_PFX
+
i
);
i8042_command
(
&
param
,
I8042_CMD_AUX_ENABLE
);
}
...
...
@@ -682,7 +686,7 @@ static int __init i8042_port_register(struct i8042_port *port)
kfree
(
port
->
serio
);
port
->
serio
=
NULL
;
i8042_ctr
|=
port
->
disable
;
return
-
1
;
return
-
EIO
;
}
printk
(
KERN_INFO
"serio: i8042 %s port at %#lx,%#lx irq %d
\n
"
,
...
...
@@ -977,85 +981,88 @@ static struct device_driver i8042_driver = {
.
shutdown
=
i8042_shutdown
,
};
static
void
__init
i8042_create_kbd_port
(
void
)
static
int
__init
i8042_create_kbd_port
(
void
)
{
struct
serio
*
serio
;
struct
i8042_port
*
port
=
&
i8042_ports
[
I8042_KBD_PORT_NO
];
serio
=
kmalloc
(
sizeof
(
struct
serio
),
GFP_KERNEL
);
if
(
serio
)
{
memset
(
serio
,
0
,
sizeof
(
struct
serio
));
serio
->
id
.
type
=
i8042_direct
?
SERIO_8042
:
SERIO_8042_XL
;
serio
->
write
=
i8042_dumbkbd
?
NULL
:
i8042_kbd_write
;
serio
->
open
=
i8042_open
;
serio
->
close
=
i8042_close
;
serio
->
start
=
i8042_start
;
serio
->
stop
=
i8042_stop
;
serio
->
port_data
=
port
;
serio
->
dev
.
parent
=
&
i8042_platform_device
->
dev
;
strlcpy
(
serio
->
name
,
"i8042 Kbd Port"
,
sizeof
(
serio
->
name
));
strlcpy
(
serio
->
phys
,
I8042_KBD_PHYS_DESC
,
sizeof
(
serio
->
phys
));
port
->
serio
=
serio
;
i8042_port_register
(
port
);
}
serio
=
kzalloc
(
sizeof
(
struct
serio
),
GFP_KERNEL
);
if
(
!
serio
)
return
-
ENOMEM
;
serio
->
id
.
type
=
i8042_direct
?
SERIO_8042
:
SERIO_8042_XL
;
serio
->
write
=
i8042_dumbkbd
?
NULL
:
i8042_kbd_write
;
serio
->
open
=
i8042_open
;
serio
->
close
=
i8042_close
;
serio
->
start
=
i8042_start
;
serio
->
stop
=
i8042_stop
;
serio
->
port_data
=
port
;
serio
->
dev
.
parent
=
&
i8042_platform_device
->
dev
;
strlcpy
(
serio
->
name
,
"i8042 Kbd Port"
,
sizeof
(
serio
->
name
));
strlcpy
(
serio
->
phys
,
I8042_KBD_PHYS_DESC
,
sizeof
(
serio
->
phys
));
port
->
serio
=
serio
;
return
i8042_port_register
(
port
);
}
static
void
__init
i8042_create_aux_port
(
void
)
static
int
__init
i8042_create_aux_port
(
void
)
{
struct
serio
*
serio
;
struct
i8042_port
*
port
=
&
i8042_ports
[
I8042_AUX_PORT_NO
];
serio
=
kmalloc
(
sizeof
(
struct
serio
),
GFP_KERNEL
);
if
(
serio
)
{
memset
(
serio
,
0
,
sizeof
(
struct
serio
));
serio
->
id
.
type
=
SERIO_8042
;
serio
->
write
=
i8042_aux_write
;
serio
->
open
=
i8042_open
;
serio
->
close
=
i8042_close
;
serio
->
start
=
i8042_start
;
serio
->
stop
=
i8042_stop
;
serio
->
port_data
=
port
;
serio
->
dev
.
parent
=
&
i8042_platform_device
->
dev
;
strlcpy
(
serio
->
name
,
"i8042 Aux Port"
,
sizeof
(
serio
->
name
));
strlcpy
(
serio
->
phys
,
I8042_AUX_PHYS_DESC
,
sizeof
(
serio
->
phys
));
port
->
serio
=
serio
;
i8042_port_register
(
port
);
}
serio
=
kzalloc
(
sizeof
(
struct
serio
),
GFP_KERNEL
);
if
(
!
serio
)
return
-
ENOMEM
;
serio
->
id
.
type
=
SERIO_8042
;
serio
->
write
=
i8042_aux_write
;
serio
->
open
=
i8042_open
;
serio
->
close
=
i8042_close
;
serio
->
start
=
i8042_start
;
serio
->
stop
=
i8042_stop
;
serio
->
port_data
=
port
;
serio
->
dev
.
parent
=
&
i8042_platform_device
->
dev
;
strlcpy
(
serio
->
name
,
"i8042 Aux Port"
,
sizeof
(
serio
->
name
));
strlcpy
(
serio
->
phys
,
I8042_AUX_PHYS_DESC
,
sizeof
(
serio
->
phys
));
port
->
serio
=
serio
;
return
i8042_port_register
(
port
);
}
static
void
__init
i8042_create_mux_port
(
int
index
)
static
int
__init
i8042_create_mux_port
(
int
index
)
{
struct
serio
*
serio
;
struct
i8042_port
*
port
=
&
i8042_ports
[
I8042_MUX_PORT_NO
+
index
];
serio
=
kmalloc
(
sizeof
(
struct
serio
),
GFP_KERNEL
);
if
(
serio
)
{
memset
(
serio
,
0
,
sizeof
(
struct
serio
));
serio
->
id
.
type
=
SERIO_8042
;
serio
->
write
=
i8042_aux_write
;
serio
->
open
=
i8042_open
;
serio
->
close
=
i8042_close
;
serio
->
start
=
i8042_start
;
serio
->
stop
=
i8042_stop
;
serio
->
port_data
=
port
;
serio
->
dev
.
parent
=
&
i8042_platform_device
->
dev
;
snprintf
(
serio
->
name
,
sizeof
(
serio
->
name
),
"i8042 Aux-%d Port"
,
index
);
snprintf
(
serio
->
phys
,
sizeof
(
serio
->
phys
),
I8042_MUX_PHYS_DESC
,
index
+
1
);
*
port
=
i8042_ports
[
I8042_AUX_PORT_NO
];
port
->
exists
=
0
;
snprintf
(
port
->
name
,
sizeof
(
port
->
name
),
"AUX%d"
,
index
);
port
->
mux
=
index
;
port
->
serio
=
serio
;
i8042_port_register
(
port
);
}
serio
=
kzalloc
(
sizeof
(
struct
serio
),
GFP_KERNEL
);
if
(
!
serio
)
return
-
ENOMEM
;
serio
->
id
.
type
=
SERIO_8042
;
serio
->
write
=
i8042_aux_write
;
serio
->
open
=
i8042_open
;
serio
->
close
=
i8042_close
;
serio
->
start
=
i8042_start
;
serio
->
stop
=
i8042_stop
;
serio
->
port_data
=
port
;
serio
->
dev
.
parent
=
&
i8042_platform_device
->
dev
;
snprintf
(
serio
->
name
,
sizeof
(
serio
->
name
),
"i8042 Aux-%d Port"
,
index
);
snprintf
(
serio
->
phys
,
sizeof
(
serio
->
phys
),
I8042_MUX_PHYS_DESC
,
index
+
1
);
*
port
=
i8042_ports
[
I8042_AUX_PORT_NO
];
port
->
exists
=
0
;
snprintf
(
port
->
name
,
sizeof
(
port
->
name
),
"AUX%d"
,
index
);
port
->
mux
=
index
;
port
->
serio
=
serio
;
return
i8042_port_register
(
port
);
}
static
int
__init
i8042_init
(
void
)
{
int
i
;
int
i
,
have_ports
=
0
;
int
err
;
dbg_init
();
...
...
@@ -1063,43 +1070,73 @@ static int __init i8042_init(void)
init_timer
(
&
i8042_timer
);
i8042_timer
.
function
=
i8042_timer_func
;
if
(
i8042_platform_init
())
return
-
EBUSY
;
err
=
i8042_platform_init
();
if
(
err
)
return
err
;
i8042_ports
[
I8042_AUX_PORT_NO
].
irq
=
I8042_AUX_IRQ
;
i8042_ports
[
I8042_KBD_PORT_NO
].
irq
=
I8042_KBD_IRQ
;
if
(
i8042_controller_init
())
{
i8042_platform_exit
()
;
return
-
ENODEV
;
err
=
-
ENODEV
;
goto
err_platform_exit
;
}
err
=
driver_register
(
&
i8042_driver
);
if
(
err
)
{
i8042_platform_exit
();
return
err
;
}
if
(
err
)
goto
err_controller_cleanup
;
i8042_platform_device
=
platform_device_register_simple
(
"i8042"
,
-
1
,
NULL
,
0
);
if
(
IS_ERR
(
i8042_platform_device
))
{
driver_unregister
(
&
i8042_driver
);
i8042_platform_exit
();
return
PTR_ERR
(
i8042_platform_device
);
err
=
PTR_ERR
(
i8042_platform_device
);
goto
err_unregister_driver
;
}
if
(
!
i8042_noaux
&&
!
i8042_check_aux
())
{
if
(
!
i8042_nomux
&&
!
i8042_check_mux
())
for
(
i
=
0
;
i
<
I8042_NUM_MUX_PORTS
;
i
++
)
i8042_create_mux_port
(
i
);
else
i8042_create_aux_port
();
if
(
!
i8042_nomux
&&
!
i8042_check_mux
())
{
for
(
i
=
0
;
i
<
I8042_NUM_MUX_PORTS
;
i
++
)
{
err
=
i8042_create_mux_port
(
i
);
if
(
err
)
goto
err_unregister_ports
;
}
}
else
{
err
=
i8042_create_aux_port
();
if
(
err
)
goto
err_unregister_ports
;
}
have_ports
=
1
;
}
i8042_create_kbd_port
();
if
(
!
i8042_nokbd
)
{
err
=
i8042_create_kbd_port
();
if
(
err
)
goto
err_unregister_ports
;
have_ports
=
1
;
}
if
(
!
have_ports
)
{
err
=
-
ENODEV
;
goto
err_unregister_device
;
}
mod_timer
(
&
i8042_timer
,
jiffies
+
I8042_POLL_PERIOD
);
return
0
;
err_unregister_ports:
for
(
i
=
0
;
i
<
I8042_NUM_PORTS
;
i
++
)
if
(
i8042_ports
[
i
].
serio
)
serio_unregister_port
(
i8042_ports
[
i
].
serio
);
err_unregister_device:
platform_device_unregister
(
i8042_platform_device
);
err_unregister_driver:
driver_unregister
(
&
i8042_driver
);
err_controller_cleanup:
i8042_controller_cleanup
();
err_platform_exit:
i8042_platform_exit
();
return
err
;
}
static
void
__exit
i8042_exit
(
void
)
...
...
drivers/usb/input/hid-core.c
View file @
7f93220b
...
...
@@ -2,7 +2,8 @@
* USB HID support for Linux
*
* Copyright (c) 1999 Andreas Gal
* Copyright (c) 2000-2001 Vojtech Pavlik <vojtech@suse.cz>
* Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
* Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
*/
/*
...
...
@@ -38,7 +39,7 @@
* Version Information
*/
#define DRIVER_VERSION "v2.
01
"
#define DRIVER_VERSION "v2.
6
"
#define DRIVER_AUTHOR "Andreas Gal, Vojtech Pavlik"
#define DRIVER_DESC "USB HID core driver"
#define DRIVER_LICENSE "GPL"
...
...
@@ -1058,8 +1059,8 @@ static int hid_submit_ctrl(struct hid_device *hid)
if
(
maxpacket
>
0
)
{
padlen
=
(
len
+
maxpacket
-
1
)
/
maxpacket
;
padlen
*=
maxpacket
;
if
(
padlen
>
HID_BUFFER_SIZE
)
padlen
=
HID_BUFFER_SIZE
;
if
(
padlen
>
hid
->
bufsize
)
padlen
=
hid
->
bufsize
;
}
else
padlen
=
0
;
hid
->
urbctrl
->
transfer_buffer_length
=
padlen
;
...
...
@@ -1096,6 +1097,7 @@ static void hid_irq_out(struct urb *urb, struct pt_regs *regs)
switch
(
urb
->
status
)
{
case
0
:
/* success */
break
;
case
-
ESHUTDOWN
:
/* unplug */
case
-
EILSEQ
:
/* unplug timeout on uhci */
unplug
=
1
;
...
...
@@ -1143,6 +1145,7 @@ static void hid_ctrl(struct urb *urb, struct pt_regs *regs)
case
0
:
/* success */
if
(
hid
->
ctrl
[
hid
->
ctrltail
].
dir
==
USB_DIR_IN
)
hid_input_report
(
hid
->
ctrl
[
hid
->
ctrltail
].
report
->
type
,
urb
,
0
,
regs
);
break
;
case
-
ESHUTDOWN
:
/* unplug */
case
-
EILSEQ
:
/* unplug timectrl on uhci */
unplug
=
1
;
...
...
@@ -1284,13 +1287,8 @@ void hid_init_reports(struct hid_device *hid)
struct
hid_report
*
report
;
int
err
,
ret
;
list_for_each_entry
(
report
,
&
hid
->
report_enum
[
HID_INPUT_REPORT
].
report_list
,
list
)
{
int
size
=
((
report
->
size
-
1
)
>>
3
)
+
1
+
hid
->
report_enum
[
HID_INPUT_REPORT
].
numbered
;
if
(
size
>
HID_BUFFER_SIZE
)
size
=
HID_BUFFER_SIZE
;
if
(
size
>
hid
->
urbin
->
transfer_buffer_length
)
hid
->
urbin
->
transfer_buffer_length
=
size
;
list_for_each_entry
(
report
,
&
hid
->
report_enum
[
HID_INPUT_REPORT
].
report_list
,
list
)
hid_submit_report
(
hid
,
report
,
USB_DIR_IN
);
}
list_for_each_entry
(
report
,
&
hid
->
report_enum
[
HID_FEATURE_REPORT
].
report_list
,
list
)
hid_submit_report
(
hid
,
report
,
USB_DIR_IN
);
...
...
@@ -1372,12 +1370,14 @@ void hid_init_reports(struct hid_device *hid)
#define USB_VENDOR_ID_A4TECH 0x09da
#define USB_DEVICE_ID_A4TECH_WCP32PU 0x0006
#define USB_VENDOR_ID_AASHIMA 0x06
D
6
#define USB_VENDOR_ID_AASHIMA 0x06
d
6
#define USB_DEVICE_ID_AASHIMA_GAMEPAD 0x0025
#define USB_DEVICE_ID_AASHIMA_PREDATOR 0x0026
#define USB_VENDOR_ID_CYPRESS 0x04b4
#define USB_DEVICE_ID_CYPRESS_MOUSE 0x0001
#define USB_DEVICE_ID_CYPRESS_HIDCOM 0x5500
#define USB_DEVICE_ID_CYPRESS_ULTRAMOUSE 0x7417
#define USB_VENDOR_ID_BERKSHIRE 0x0c98
#define USB_DEVICE_ID_BERKSHIRE_PCWD 0x1140
...
...
@@ -1432,7 +1432,7 @@ void hid_init_reports(struct hid_device *hid)
#define USB_DEVICE_ID_VERNIER_CYCLOPS 0x0004
#define USB_VENDOR_ID_LD 0x0f11
#define USB_DEVICE_ID_CASSY
0x1000
#define USB_DEVICE_ID_CASSY
0x1000
#define USB_DEVICE_ID_POCKETCASSY 0x1010
#define USB_DEVICE_ID_MOBILECASSY 0x1020
#define USB_DEVICE_ID_JWM 0x1080
...
...
@@ -1445,7 +1445,8 @@ void hid_init_reports(struct hid_device *hid)
#define USB_DEVICE_ID_POWERCONTROL 0x2030
#define USB_VENDOR_ID_APPLE 0x05ac
#define USB_DEVICE_ID_APPLE_BLUETOOTH 0x1000
#define USB_DEVICE_ID_APPLE_POWERMOUSE 0x0304
#define USB_DEVICE_ID_APPLE_BLUETOOTH 0x1000
/*
* Alphabetically sorted blacklist by quirk type.
...
...
@@ -1471,6 +1472,7 @@ static struct hid_blacklist {
{
USB_VENDOR_ID_CODEMERCS
,
USB_DEVICE_ID_CODEMERCS_IOW48
,
HID_QUIRK_IGNORE
},
{
USB_VENDOR_ID_CODEMERCS
,
USB_DEVICE_ID_CODEMERCS_IOW28
,
HID_QUIRK_IGNORE
},
{
USB_VENDOR_ID_CYPRESS
,
USB_DEVICE_ID_CYPRESS_HIDCOM
,
HID_QUIRK_IGNORE
},
{
USB_VENDOR_ID_CYPRESS
,
USB_DEVICE_ID_CYPRESS_ULTRAMOUSE
,
HID_QUIRK_IGNORE
},
{
USB_VENDOR_ID_DELORME
,
USB_DEVICE_ID_DELORME_EARTHMATE
,
HID_QUIRK_IGNORE
},
{
USB_VENDOR_ID_DELORME
,
USB_DEVICE_ID_DELORME_EM_LT20
,
HID_QUIRK_IGNORE
},
{
USB_VENDOR_ID_ESSENTIAL_REALITY
,
USB_DEVICE_ID_ESSENTIAL_REALITY_P5
,
HID_QUIRK_IGNORE
},
...
...
@@ -1551,10 +1553,12 @@ static struct hid_blacklist {
{
USB_VENDOR_ID_CHICONY
,
USB_DEVICE_ID_CHICONY_USBHUB_KB
,
HID_QUIRK_NOGET
},
{
USB_VENDOR_ID_TANGTOP
,
USB_DEVICE_ID_TANGTOP_USBPS2
,
HID_QUIRK_NOGET
},
{
USB_VENDOR_ID_APPLE
,
USB_DEVICE_ID_APPLE_POWERMOUSE
,
HID_QUIRK_2WHEEL_POWERMOUSE
},
{
USB_VENDOR_ID_A4TECH
,
USB_DEVICE_ID_A4TECH_WCP32PU
,
HID_QUIRK_2WHEEL_MOUSE_HACK_7
},
{
USB_VENDOR_ID_CYPRESS
,
USB_DEVICE_ID_CYPRESS_MOUSE
,
HID_QUIRK_2WHEEL_MOUSE_HACK_5
},
{
USB_VENDOR_ID_AASHIMA
,
USB_DEVICE_ID_AASHIMA_GAMEPAD
,
HID_QUIRK_BADPAD
},
{
USB_VENDOR_ID_AASHIMA
,
USB_DEVICE_ID_AASHIMA_PREDATOR
,
HID_QUIRK_BADPAD
},
{
USB_VENDOR_ID_ALPS
,
USB_DEVICE_ID_IBM_GAMEPAD
,
HID_QUIRK_BADPAD
},
{
USB_VENDOR_ID_CHIC
,
USB_DEVICE_ID_CHIC_GAMEPAD
,
HID_QUIRK_BADPAD
},
{
USB_VENDOR_ID_HAPP
,
USB_DEVICE_ID_UGCI_DRIVING
,
HID_QUIRK_BADPAD
|
HID_QUIRK_MULTI_INPUT
},
...
...
@@ -1567,15 +1571,32 @@ static struct hid_blacklist {
{
0
,
0
}
};
/*
* Traverse the supplied list of reports and find the longest
*/
static
void
hid_find_max_report
(
struct
hid_device
*
hid
,
unsigned
int
type
,
int
*
max
)
{
struct
hid_report
*
report
;
int
size
;
list_for_each_entry
(
report
,
&
hid
->
report_enum
[
type
].
report_list
,
list
)
{
size
=
((
report
->
size
-
1
)
>>
3
)
+
1
;
if
(
type
==
HID_INPUT_REPORT
&&
hid
->
report_enum
[
type
].
numbered
)
size
++
;
if
(
*
max
<
size
)
*
max
=
size
;
}
}
static
int
hid_alloc_buffers
(
struct
usb_device
*
dev
,
struct
hid_device
*
hid
)
{
if
(
!
(
hid
->
inbuf
=
usb_buffer_alloc
(
dev
,
HID_BUFFER_SIZE
,
SLAB_ATOMIC
,
&
hid
->
inbuf_dma
)))
if
(
!
(
hid
->
inbuf
=
usb_buffer_alloc
(
dev
,
hid
->
bufsize
,
SLAB_ATOMIC
,
&
hid
->
inbuf_dma
)))
return
-
1
;
if
(
!
(
hid
->
outbuf
=
usb_buffer_alloc
(
dev
,
HID_BUFFER_SIZE
,
SLAB_ATOMIC
,
&
hid
->
outbuf_dma
)))
if
(
!
(
hid
->
outbuf
=
usb_buffer_alloc
(
dev
,
hid
->
bufsize
,
SLAB_ATOMIC
,
&
hid
->
outbuf_dma
)))
return
-
1
;
if
(
!
(
hid
->
cr
=
usb_buffer_alloc
(
dev
,
sizeof
(
*
(
hid
->
cr
)),
SLAB_ATOMIC
,
&
hid
->
cr_dma
)))
return
-
1
;
if
(
!
(
hid
->
ctrlbuf
=
usb_buffer_alloc
(
dev
,
HID_BUFFER_SIZE
,
SLAB_ATOMIC
,
&
hid
->
ctrlbuf_dma
)))
if
(
!
(
hid
->
ctrlbuf
=
usb_buffer_alloc
(
dev
,
hid
->
bufsize
,
SLAB_ATOMIC
,
&
hid
->
ctrlbuf_dma
)))
return
-
1
;
return
0
;
...
...
@@ -1584,13 +1605,13 @@ static int hid_alloc_buffers(struct usb_device *dev, struct hid_device *hid)
static
void
hid_free_buffers
(
struct
usb_device
*
dev
,
struct
hid_device
*
hid
)
{
if
(
hid
->
inbuf
)
usb_buffer_free
(
dev
,
HID_BUFFER_SIZE
,
hid
->
inbuf
,
hid
->
inbuf_dma
);
usb_buffer_free
(
dev
,
hid
->
bufsize
,
hid
->
inbuf
,
hid
->
inbuf_dma
);
if
(
hid
->
outbuf
)
usb_buffer_free
(
dev
,
HID_BUFFER_SIZE
,
hid
->
outbuf
,
hid
->
outbuf_dma
);
usb_buffer_free
(
dev
,
hid
->
bufsize
,
hid
->
outbuf
,
hid
->
outbuf_dma
);
if
(
hid
->
cr
)
usb_buffer_free
(
dev
,
sizeof
(
*
(
hid
->
cr
)),
hid
->
cr
,
hid
->
cr_dma
);
if
(
hid
->
ctrlbuf
)
usb_buffer_free
(
dev
,
HID_BUFFER_SIZE
,
hid
->
ctrlbuf
,
hid
->
ctrlbuf_dma
);
usb_buffer_free
(
dev
,
hid
->
bufsize
,
hid
->
ctrlbuf
,
hid
->
ctrlbuf_dma
);
}
static
struct
hid_device
*
usb_hid_configure
(
struct
usb_interface
*
intf
)
...
...
@@ -1601,7 +1622,7 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
struct
hid_device
*
hid
;
unsigned
quirks
=
0
,
rsize
=
0
;
char
*
buf
,
*
rdesc
;
int
n
;
int
n
,
insize
=
0
;
for
(
n
=
0
;
hid_blacklist
[
n
].
idVendor
;
n
++
)
if
((
hid_blacklist
[
n
].
idVendor
==
le16_to_cpu
(
dev
->
descriptor
.
idVendor
))
&&
...
...
@@ -1655,6 +1676,19 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
kfree
(
rdesc
);
hid
->
quirks
=
quirks
;
hid
->
bufsize
=
HID_MIN_BUFFER_SIZE
;
hid_find_max_report
(
hid
,
HID_INPUT_REPORT
,
&
hid
->
bufsize
);
hid_find_max_report
(
hid
,
HID_OUTPUT_REPORT
,
&
hid
->
bufsize
);
hid_find_max_report
(
hid
,
HID_FEATURE_REPORT
,
&
hid
->
bufsize
);
if
(
hid
->
bufsize
>
HID_MAX_BUFFER_SIZE
)
hid
->
bufsize
=
HID_MAX_BUFFER_SIZE
;
hid_find_max_report
(
hid
,
HID_INPUT_REPORT
,
&
insize
);
if
(
insize
>
HID_MAX_BUFFER_SIZE
)
insize
=
HID_MAX_BUFFER_SIZE
;
if
(
hid_alloc_buffers
(
dev
,
hid
))
{
hid_free_buffers
(
dev
,
hid
);
goto
fail
;
...
...
@@ -1685,7 +1719,7 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
if
(
!
(
hid
->
urbin
=
usb_alloc_urb
(
0
,
GFP_KERNEL
)))
goto
fail
;
pipe
=
usb_rcvintpipe
(
dev
,
endpoint
->
bEndpointAddress
);
usb_fill_int_urb
(
hid
->
urbin
,
dev
,
pipe
,
hid
->
inbuf
,
0
,
usb_fill_int_urb
(
hid
->
urbin
,
dev
,
pipe
,
hid
->
inbuf
,
insize
,
hid_irq_in
,
hid
,
interval
);
hid
->
urbin
->
transfer_dma
=
hid
->
inbuf_dma
;
hid
->
urbin
->
transfer_flags
|=
URB_NO_TRANSFER_DMA_MAP
;
...
...
drivers/usb/input/hid-debug.h
View file @
7f93220b
...
...
@@ -85,6 +85,23 @@ static const struct hid_usage_entry hid_usage_table[] = {
{
0
,
0x91
,
"D-PadDown"
},
{
0
,
0x92
,
"D-PadRight"
},
{
0
,
0x93
,
"D-PadLeft"
},
{
2
,
0
,
"Simulation"
},
{
0
,
0xb0
,
"Aileron"
},
{
0
,
0xb1
,
"AileronTrim"
},
{
0
,
0xb2
,
"Anti-Torque"
},
{
0
,
0xb3
,
"Autopilot"
},
{
0
,
0xb4
,
"Chaff"
},
{
0
,
0xb5
,
"Collective"
},
{
0
,
0xb6
,
"DiveBrake"
},
{
0
,
0xb7
,
"ElectronicCountermeasures"
},
{
0
,
0xb8
,
"Elevator"
},
{
0
,
0xb9
,
"ElevatorTrim"
},
{
0
,
0xba
,
"Rudder"
},
{
0
,
0xbb
,
"Throttle"
},
{
0
,
0xbc
,
"FlightCommunications"
},
{
0
,
0xbd
,
"FlareRelease"
},
{
0
,
0xbe
,
"LandingGear"
},
{
0
,
0xbf
,
"ToeBrake"
},
{
7
,
0
,
"Keyboard"
},
{
8
,
0
,
"LED"
},
{
0
,
0x01
,
"NumLock"
},
...
...
@@ -92,6 +109,7 @@ static const struct hid_usage_entry hid_usage_table[] = {
{
0
,
0x03
,
"ScrollLock"
},
{
0
,
0x04
,
"Compose"
},
{
0
,
0x05
,
"Kana"
},
{
0
,
0x4b
,
"GenericIndicator"
},
{
9
,
0
,
"Button"
},
{
10
,
0
,
"Ordinal"
},
{
12
,
0
,
"Consumer"
},
...
...
@@ -574,7 +592,8 @@ static char *keys[KEY_MAX + 1] = {
[
KEY_EXIT
]
=
"Exit"
,
[
KEY_MOVE
]
=
"Move"
,
[
KEY_EDIT
]
=
"Edit"
,
[
KEY_SCROLLUP
]
=
"ScrollUp"
,
[
KEY_SCROLLDOWN
]
=
"ScrollDown"
,
[
KEY_KPLEFTPAREN
]
=
"KPLeftParenthesis"
,
[
KEY_KPRIGHTPAREN
]
=
"KPRightParenthesis"
,
[
KEY_F13
]
=
"F13"
,
[
KEY_KPRIGHTPAREN
]
=
"KPRightParenthesis"
,
[
KEY_NEW
]
=
"New"
,
[
KEY_REDO
]
=
"Redo"
,
[
KEY_F13
]
=
"F13"
,
[
KEY_F14
]
=
"F14"
,
[
KEY_F15
]
=
"F15"
,
[
KEY_F16
]
=
"F16"
,
[
KEY_F17
]
=
"F17"
,
[
KEY_F18
]
=
"F18"
,
[
KEY_F19
]
=
"F19"
,
...
...
@@ -584,15 +603,15 @@ static char *keys[KEY_MAX + 1] = {
[
KEY_PAUSECD
]
=
"PauseCD"
,
[
KEY_PROG3
]
=
"Prog3"
,
[
KEY_PROG4
]
=
"Prog4"
,
[
KEY_SUSPEND
]
=
"Suspend"
,
[
KEY_CLOSE
]
=
"Close"
,
[
KEY_PLAY
]
=
"Play"
,
[
KEY_FASTFORWARD
]
=
"Fast
Forward"
,
[
KEY_BASSBOOST
]
=
"Bass
Boost"
,
[
KEY_FASTFORWARD
]
=
"Fast
Forward"
,
[
KEY_BASSBOOST
]
=
"Bass
Boost"
,
[
KEY_PRINT
]
=
"Print"
,
[
KEY_HP
]
=
"HP"
,
[
KEY_CAMERA
]
=
"Camera"
,
[
KEY_SOUND
]
=
"Sound"
,
[
KEY_QUESTION
]
=
"Question"
,
[
KEY_EMAIL
]
=
"Email"
,
[
KEY_CHAT
]
=
"Chat"
,
[
KEY_SEARCH
]
=
"Search"
,
[
KEY_CONNECT
]
=
"Connect"
,
[
KEY_FINANCE
]
=
"Finance"
,
[
KEY_SPORT
]
=
"Sport"
,
[
KEY_SHOP
]
=
"Shop"
,
[
KEY_ALTERASE
]
=
"Alternate
Erase"
,
[
KEY_CANCEL
]
=
"Cancel"
,
[
KEY_BRIGHTNESSDOWN
]
=
"Brightness
down"
,
[
KEY_BRIGHTNESSUP
]
=
"Brightness u
p"
,
[
KEY_ALTERASE
]
=
"AlternateErase"
,
[
KEY_CANCEL
]
=
"Cancel"
,
[
KEY_BRIGHTNESSDOWN
]
=
"Brightness
Down"
,
[
KEY_BRIGHTNESSUP
]
=
"BrightnessU
p"
,
[
KEY_MEDIA
]
=
"Media"
,
[
KEY_UNKNOWN
]
=
"Unknown"
,
[
BTN_0
]
=
"Btn0"
,
[
BTN_1
]
=
"Btn1"
,
[
BTN_2
]
=
"Btn2"
,
[
BTN_3
]
=
"Btn3"
,
...
...
@@ -622,8 +641,8 @@ static char *keys[KEY_MAX + 1] = {
[
BTN_TOOL_AIRBRUSH
]
=
"ToolAirbrush"
,
[
BTN_TOOL_FINGER
]
=
"ToolFinger"
,
[
BTN_TOOL_MOUSE
]
=
"ToolMouse"
,
[
BTN_TOOL_LENS
]
=
"ToolLens"
,
[
BTN_TOUCH
]
=
"Touch"
,
[
BTN_STYLUS
]
=
"Stylus"
,
[
BTN_STYLUS2
]
=
"Stylus2"
,
[
BTN_TOOL_DOUBLETAP
]
=
"Tool
Doublet
ap"
,
[
BTN_TOOL_TRIPLETAP
]
=
"Tool
Triplet
ap"
,
[
BTN_GEAR_DOWN
]
=
"WheelBtn"
,
[
BTN_STYLUS2
]
=
"Stylus2"
,
[
BTN_TOOL_DOUBLETAP
]
=
"Tool
DoubleT
ap"
,
[
BTN_TOOL_TRIPLETAP
]
=
"Tool
TripleT
ap"
,
[
BTN_GEAR_DOWN
]
=
"WheelBtn"
,
[
BTN_GEAR_UP
]
=
"Gear up"
,
[
KEY_OK
]
=
"Ok"
,
[
KEY_SELECT
]
=
"Select"
,
[
KEY_GOTO
]
=
"Goto"
,
[
KEY_CLEAR
]
=
"Clear"
,
[
KEY_POWER2
]
=
"Power2"
,
...
...
@@ -659,6 +678,9 @@ static char *keys[KEY_MAX + 1] = {
[
KEY_TWEN
]
=
"TWEN"
,
[
KEY_DEL_EOL
]
=
"DeleteEOL"
,
[
KEY_DEL_EOS
]
=
"DeleteEOS"
,
[
KEY_INS_LINE
]
=
"InsertLine"
,
[
KEY_DEL_LINE
]
=
"DeleteLine"
,
[
KEY_SEND
]
=
"Send"
,
[
KEY_REPLY
]
=
"Reply"
,
[
KEY_FORWARDMAIL
]
=
"ForwardMail"
,
[
KEY_SAVE
]
=
"Save"
,
[
KEY_DOCUMENTS
]
=
"Documents"
,
};
static
char
*
relatives
[
REL_MAX
+
1
]
=
{
...
...
drivers/usb/input/hid-input.c
View file @
7f93220b
...
...
@@ -78,8 +78,8 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
{
struct
input_dev
*
input
=
&
hidinput
->
input
;
struct
hid_device
*
device
=
hidinput
->
input
.
private
;
int
max
,
code
;
unsigned
long
*
bit
;
int
max
=
0
,
code
;
unsigned
long
*
bit
=
NULL
;
field
->
hidinput
=
hidinput
;
...
...
@@ -131,6 +131,15 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
map_key
(
code
);
break
;
case
HID_UP_SIMULATION
:
switch
(
usage
->
hid
&
0xffff
)
{
case
0xba
:
map_abs
(
ABS_RUDDER
);
break
;
case
0xbb
:
map_abs
(
ABS_THROTTLE
);
break
;
}
break
;
case
HID_UP_GENDESK
:
if
((
usage
->
hid
&
0xf0
)
==
0x80
)
{
/* SystemControl */
...
...
@@ -238,8 +247,12 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
case
0x000
:
goto
ignore
;
case
0x034
:
map_key_clear
(
KEY_SLEEP
);
break
;
case
0x036
:
map_key_clear
(
BTN_MISC
);
break
;
case
0x045
:
map_key_clear
(
KEY_RADIO
);
break
;
case
0x08a
:
map_key_clear
(
KEY_WWW
);
break
;
case
0x08d
:
map_key_clear
(
KEY_PROGRAM
);
break
;
case
0x095
:
map_key_clear
(
KEY_HELP
);
break
;
case
0x09c
:
map_key_clear
(
KEY_CHANNELUP
);
break
;
case
0x09d
:
map_key_clear
(
KEY_CHANNELDOWN
);
break
;
case
0x0b0
:
map_key_clear
(
KEY_PLAY
);
break
;
case
0x0b1
:
map_key_clear
(
KEY_PAUSE
);
break
;
case
0x0b2
:
map_key_clear
(
KEY_RECORD
);
break
;
...
...
@@ -259,6 +272,11 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
case
0x18a
:
map_key_clear
(
KEY_MAIL
);
break
;
case
0x192
:
map_key_clear
(
KEY_CALC
);
break
;
case
0x194
:
map_key_clear
(
KEY_FILE
);
break
;
case
0x1a7
:
map_key_clear
(
KEY_DOCUMENTS
);
break
;
case
0x201
:
map_key_clear
(
KEY_NEW
);
break
;
case
0x207
:
map_key_clear
(
KEY_SAVE
);
break
;
case
0x208
:
map_key_clear
(
KEY_PRINT
);
break
;
case
0x209
:
map_key_clear
(
KEY_PROPS
);
break
;
case
0x21a
:
map_key_clear
(
KEY_UNDO
);
break
;
case
0x21b
:
map_key_clear
(
KEY_COPY
);
break
;
case
0x21c
:
map_key_clear
(
KEY_CUT
);
break
;
...
...
@@ -271,7 +289,11 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
case
0x227
:
map_key_clear
(
KEY_REFRESH
);
break
;
case
0x22a
:
map_key_clear
(
KEY_BOOKMARKS
);
break
;
case
0x238
:
map_rel
(
REL_HWHEEL
);
break
;
default:
goto
unknown
;
case
0x279
:
map_key_clear
(
KEY_REDO
);
break
;
case
0x289
:
map_key_clear
(
KEY_REPLY
);
break
;
case
0x28b
:
map_key_clear
(
KEY_FORWARDMAIL
);
break
;
case
0x28c
:
map_key_clear
(
KEY_SEND
);
break
;
default:
goto
ignore
;
}
break
;
...
...
@@ -296,9 +318,42 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
break
;
case
HID_UP_MSVENDOR
:
goto
ignore
;
case
HID_UP_CUSTOM
:
/* Reported on Logitech and Powerbook USB keyboards */
set_bit
(
EV_REP
,
input
->
evbit
);
switch
(
usage
->
hid
&
HID_USAGE
)
{
case
0x003
:
map_key_clear
(
KEY_FN
);
break
;
default:
goto
ignore
;
}
break
;
case
HID_UP_LOGIVENDOR
:
/* Reported on Logitech Ultra X Media Remote */
set_bit
(
EV_REP
,
input
->
evbit
);
switch
(
usage
->
hid
&
HID_USAGE
)
{
case
0x004
:
map_key_clear
(
KEY_AGAIN
);
break
;
case
0x00d
:
map_key_clear
(
KEY_HOME
);
break
;
case
0x024
:
map_key_clear
(
KEY_SHUFFLE
);
break
;
case
0x025
:
map_key_clear
(
KEY_TV
);
break
;
case
0x026
:
map_key_clear
(
KEY_MENU
);
break
;
case
0x031
:
map_key_clear
(
KEY_AUDIO
);
break
;
case
0x032
:
map_key_clear
(
KEY_SUBTITLE
);
break
;
case
0x033
:
map_key_clear
(
KEY_LAST
);
break
;
case
0x047
:
map_key_clear
(
KEY_MP3
);
break
;
case
0x048
:
map_key_clear
(
KEY_DVD
);
break
;
case
0x049
:
map_key_clear
(
KEY_MEDIA
);
break
;
case
0x04a
:
map_key_clear
(
KEY_VIDEO
);
break
;
case
0x04b
:
map_key_clear
(
KEY_ANGLE
);
break
;
case
0x04c
:
map_key_clear
(
KEY_LANGUAGE
);
break
;
case
0x04d
:
map_key_clear
(
KEY_SUBTITLE
);
break
;
case
0x051
:
map_key_clear
(
KEY_RED
);
break
;
case
0x052
:
map_key_clear
(
KEY_CLOSE
);
break
;
default:
goto
ignore
;
}
break
;
case
HID_UP_PID
:
set_bit
(
EV_FF
,
input
->
evbit
);
...
...
@@ -349,6 +404,9 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
if
(
usage
->
code
>
max
)
goto
ignore
;
if
(((
device
->
quirks
&
(
HID_QUIRK_2WHEEL_POWERMOUSE
))
&&
(
usage
->
hid
==
0x00010032
)))
map_rel
(
REL_HWHEEL
);
if
((
device
->
quirks
&
(
HID_QUIRK_2WHEEL_MOUSE_HACK_7
|
HID_QUIRK_2WHEEL_MOUSE_HACK_5
))
&&
(
usage
->
type
==
EV_REL
)
&&
(
usage
->
code
==
REL_WHEEL
))
set_bit
(
REL_HWHEEL
,
bit
);
...
...
drivers/usb/input/hid.h
View file @
7f93220b
...
...
@@ -173,6 +173,7 @@ struct hid_item {
#define HID_UP_UNDEFINED 0x00000000
#define HID_UP_GENDESK 0x00010000
#define HID_UP_SIMULATION 0x00020000
#define HID_UP_KEYBOARD 0x00070000
#define HID_UP_LED 0x00080000
#define HID_UP_BUTTON 0x00090000
...
...
@@ -182,6 +183,8 @@ struct hid_item {
#define HID_UP_PID 0x000f0000
#define HID_UP_HPVENDOR 0xff7f0000
#define HID_UP_MSVENDOR 0xff000000
#define HID_UP_CUSTOM 0x00ff0000
#define HID_UP_LOGIVENDOR 0xffbc0000
#define HID_USAGE 0x0000ffff
...
...
@@ -242,6 +245,7 @@ struct hid_item {
#define HID_QUIRK_2WHEEL_MOUSE_HACK_7 0x080
#define HID_QUIRK_2WHEEL_MOUSE_HACK_5 0x100
#define HID_QUIRK_2WHEEL_MOUSE_HACK_ON 0x200
#define HID_QUIRK_2WHEEL_POWERMOUSE 0x400
/*
* This is the global environment of the parser. This information is
...
...
@@ -348,7 +352,8 @@ struct hid_report_enum {
#define HID_REPORT_TYPES 3
#define HID_BUFFER_SIZE 64
/* use 64 for compatibility with all possible packetlen */
#define HID_MIN_BUFFER_SIZE 64
/* make sure there is at least a packet size of space */
#define HID_MAX_BUFFER_SIZE 4096
/* 4kb */
#define HID_CONTROL_FIFO_SIZE 256
/* to init devices with >100 reports */
#define HID_OUTPUT_FIFO_SIZE 64
...
...
@@ -386,6 +391,8 @@ struct hid_device { /* device report descriptor */
unsigned
long
iofl
;
/* I/O flags (CTRL_RUNNING, OUT_RUNNING) */
unsigned
int
bufsize
;
/* URB buffer size */
struct
urb
*
urbin
;
/* Input URB */
char
*
inbuf
;
/* Input buffer */
dma_addr_t
inbuf_dma
;
/* Input buffer dma */
...
...
drivers/usb/input/hiddev.c
View file @
7f93220b
...
...
@@ -507,6 +507,7 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
return
-
EINVAL
;
hid_submit_report
(
hid
,
report
,
USB_DIR_OUT
);
hid_wait_io
(
hid
);
return
0
;
...
...
include/linux/input.h
View file @
7f93220b
...
...
@@ -289,6 +289,8 @@ struct input_absinfo {
#define KEY_SCROLLDOWN 178
#define KEY_KPLEFTPAREN 179
#define KEY_KPRIGHTPAREN 180
#define KEY_NEW 181
#define KEY_REDO 182
#define KEY_F13 183
#define KEY_F14 184
...
...
@@ -335,6 +337,12 @@ struct input_absinfo {
#define KEY_KBDILLUMDOWN 229
#define KEY_KBDILLUMUP 230
#define KEY_SEND 231
#define KEY_REPLY 232
#define KEY_FORWARDMAIL 233
#define KEY_SAVE 234
#define KEY_DOCUMENTS 235
#define KEY_UNKNOWN 240
#define BTN_MISC 0x100
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment