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
Kirill Smelkov
linux
Commits
73df7566
Commit
73df7566
authored
Aug 16, 2004
by
Vojtech Pavlik
Browse files
Options
Browse Files
Download
Plain Diff
Merge suse.cz:/data/bk/linus into suse.cz:/data/bk/input
parents
4d802161
0a521afd
Changes
65
Hide whitespace changes
Inline
Side-by-side
Showing
65 changed files
with
2967 additions
and
1261 deletions
+2967
-1261
Documentation/input/joystick-parport.txt
Documentation/input/joystick-parport.txt
+11
-2
Documentation/kernel-parameters.txt
Documentation/kernel-parameters.txt
+6
-0
MAINTAINERS
MAINTAINERS
+8
-9
drivers/Makefile
drivers/Makefile
+3
-1
drivers/char/keyboard.c
drivers/char/keyboard.c
+25
-8
drivers/input/gameport/emu10k1-gp.c
drivers/input/gameport/emu10k1-gp.c
+3
-0
drivers/input/joydev.c
drivers/input/joydev.c
+4
-2
drivers/input/joystick/Kconfig
drivers/input/joystick/Kconfig
+1
-1
drivers/input/joystick/gamecon.c
drivers/input/joystick/gamecon.c
+102
-92
drivers/input/joystick/iforce/iforce-main.c
drivers/input/joystick/iforce/iforce-main.c
+2
-2
drivers/input/joystick/iforce/iforce-serio.c
drivers/input/joystick/iforce/iforce-serio.c
+11
-7
drivers/input/joystick/iforce/iforce.h
drivers/input/joystick/iforce/iforce.h
+1
-1
drivers/input/joystick/magellan.c
drivers/input/joystick/magellan.c
+15
-9
drivers/input/joystick/spaceball.c
drivers/input/joystick/spaceball.c
+15
-9
drivers/input/joystick/spaceorb.c
drivers/input/joystick/spaceorb.c
+15
-9
drivers/input/joystick/stinger.c
drivers/input/joystick/stinger.c
+15
-9
drivers/input/joystick/tmdc.c
drivers/input/joystick/tmdc.c
+1
-1
drivers/input/joystick/twidjoy.c
drivers/input/joystick/twidjoy.c
+12
-8
drivers/input/joystick/warrior.c
drivers/input/joystick/warrior.c
+15
-9
drivers/input/keyboard/atkbd.c
drivers/input/keyboard/atkbd.c
+214
-71
drivers/input/keyboard/lkkbd.c
drivers/input/keyboard/lkkbd.c
+15
-9
drivers/input/keyboard/newtonkbd.c
drivers/input/keyboard/newtonkbd.c
+15
-9
drivers/input/keyboard/sunkbd.c
drivers/input/keyboard/sunkbd.c
+15
-9
drivers/input/keyboard/xtkbd.c
drivers/input/keyboard/xtkbd.c
+15
-9
drivers/input/misc/Kconfig
drivers/input/misc/Kconfig
+1
-1
drivers/input/misc/uinput.c
drivers/input/misc/uinput.c
+3
-0
drivers/input/mouse/Kconfig
drivers/input/mouse/Kconfig
+0
-2
drivers/input/mouse/logips2pp.c
drivers/input/mouse/logips2pp.c
+1
-1
drivers/input/mouse/psmouse-base.c
drivers/input/mouse/psmouse-base.c
+214
-98
drivers/input/mouse/psmouse.h
drivers/input/mouse/psmouse.h
+22
-18
drivers/input/mouse/sermouse.c
drivers/input/mouse/sermouse.c
+15
-9
drivers/input/mouse/synaptics.c
drivers/input/mouse/synaptics.c
+27
-27
drivers/input/mouse/vsxxxaa.c
drivers/input/mouse/vsxxxaa.c
+15
-9
drivers/input/mousedev.c
drivers/input/mousedev.c
+174
-63
drivers/input/serio/Kconfig
drivers/input/serio/Kconfig
+16
-0
drivers/input/serio/Makefile
drivers/input/serio/Makefile
+1
-0
drivers/input/serio/ambakmi.c
drivers/input/serio/ambakmi.c
+25
-19
drivers/input/serio/ct82c710.c
drivers/input/serio/ct82c710.c
+59
-45
drivers/input/serio/gscps2.c
drivers/input/serio/gscps2.c
+38
-24
drivers/input/serio/i8042-io.h
drivers/input/serio/i8042-io.h
+31
-0
drivers/input/serio/i8042.c
drivers/input/serio/i8042.c
+205
-148
drivers/input/serio/i8042.h
drivers/input/serio/i8042.h
+7
-0
drivers/input/serio/maceps2.c
drivers/input/serio/maceps2.c
+51
-35
drivers/input/serio/parkbd.c
drivers/input/serio/parkbd.c
+30
-17
drivers/input/serio/pcips2.c
drivers/input/serio/pcips2.c
+29
-25
drivers/input/serio/q40kbd.c
drivers/input/serio/q40kbd.c
+89
-28
drivers/input/serio/rpckbd.c
drivers/input/serio/rpckbd.c
+38
-10
drivers/input/serio/sa1111ps2.c
drivers/input/serio/sa1111ps2.c
+24
-17
drivers/input/serio/serio.c
drivers/input/serio/serio.c
+457
-119
drivers/input/serio/serio_raw.c
drivers/input/serio/serio_raw.c
+390
-0
drivers/input/serio/serport.c
drivers/input/serio/serport.c
+25
-24
drivers/input/touchscreen/gunze.c
drivers/input/touchscreen/gunze.c
+15
-9
drivers/input/touchscreen/h3600_ts_input.c
drivers/input/touchscreen/h3600_ts_input.c
+15
-9
drivers/input/tsdev.c
drivers/input/tsdev.c
+191
-110
drivers/serial/sunsu.c
drivers/serial/sunsu.c
+49
-40
drivers/serial/sunzilog.c
drivers/serial/sunzilog.c
+51
-29
drivers/usb/input/hid-core.c
drivers/usb/input/hid-core.c
+7
-2
drivers/usb/input/hiddev.c
drivers/usb/input/hiddev.c
+16
-19
fs/compat_ioctl.c
fs/compat_ioctl.c
+2
-0
include/asm-ppc/8253pit.h
include/asm-ppc/8253pit.h
+10
-0
include/asm-ppc64/8253pit.h
include/asm-ppc64/8253pit.h
+10
-0
include/linux/compat_ioctl.h
include/linux/compat_ioctl.h
+17
-0
include/linux/hiddev.h
include/linux/hiddev.h
+7
-1
include/linux/input.h
include/linux/input.h
+2
-0
include/linux/serio.h
include/linux/serio.h
+49
-17
No files found.
Documentation/input/joystick-parport.txt
View file @
73df7566
...
...
@@ -335,6 +335,7 @@ controller (compatible with DirectPadPro):
* Analog PSX Pad (red mode)
* Analog PSX Pad (green mode)
* PSX Rumble Pad
* PSX DDR Pad
2.4 Sega
~~~~~~~~
...
...
@@ -452,14 +453,22 @@ uses the following kernel/module command line:
5 | Multisystem 2-button joystick
6 | N64 pad
7 | Sony PSX controller
8 | Sony PSX DDR controller
The exact type of the PSX controller type is autoprobed
, so you must have
your controller plugged in before initializing
.
The exact type of the PSX controller type is autoprobed
when used so
hot swapping should work (but is not recomended)
.
Should you want to use more than one of parallel ports at once, you can use
gamecon.map2 and gamecon.map3 as additional command line parameters for two
more parallel ports.
There are two options specific to PSX driver portion. gamecon.psx_delay sets
the command delay when talking to the controllers. The default of 25 should
work but you can try lowering it for better performace. If your pads don't
respond try raising it untill they work. Setting the type to 8 allows the
driver to be used with Dance Dance Revolution or similar games. Arrow keys are
registered as key presses instead of X and Y axes.
3.2 db9.c
~~~~~~~~~
Apart from making an interface, there is nothing difficult on using the
...
...
Documentation/kernel-parameters.txt
View file @
73df7566
...
...
@@ -650,6 +650,12 @@ running once the system is up.
mga= [HW,DRM]
mousedev.tap_time=
[MOUSE] Maximum time between finger touching and
leaving touchpad surface for touch to be considered
a tap and be reported as a left button click (for
touchpads working in absolute mode only).
Format: <msecs>
mousedev.xres= [MOUSE] Horizontal screen resolution, used for devices
reporting absolute coordinates, such as tablets
mousedev.yres= [MOUSE] Vertical screen resolution, used for devices
...
...
MAINTAINERS
View file @
73df7566
...
...
@@ -1060,6 +1060,13 @@ M: lethal@chaoticdreams.org
L: linux-fbdev-devel@lists.sourceforge.net
S: Maintained
INPUT (KEYBOARD, MOUSE, JOYSTICK) DRIVERS
P: Vojtech Pavlik
M: vojtech@suse.cz
L: linux-input@atrey.karlin.mff.cuni.cz
L: linux-joystick@atrey.karlin.mff.cuni.cz
S: Maintained
INTEL APIC/IOAPIC, LOWLEVEL X86 SMP SUPPORT
P: Ingo Molnar
M: mingo@redhat.com
...
...
@@ -1178,13 +1185,6 @@ L: jfs-discussion@oss.software.ibm.com
W: http://oss.software.ibm.com/jfs/
S: Supported
JOYSTICK DRIVER
P: Vojtech Pavlik
M: vojtech@suse.cz
L: linux-joystick@atrey.karlin.mff.cuni.cz
W: http://www.suse.cz/development/joystick/
S: Maintained
KCONFIG
P: Roman Zippel
M: zippel@linux-m68k.org
...
...
@@ -2165,12 +2165,11 @@ M: dbrownell@users.sourceforge.net
L: linux-usb-devel@lists.sourceforge.net
S: Maintained
USB HID/HIDBP
/INPUT
DRIVERS
USB HID/HIDBP DRIVERS
P: Vojtech Pavlik
M: vojtech@suse.cz
L: linux-usb-users@lists.sourceforge.net
L: linux-usb-devel@lists.sourceforge.net
W: http://www.suse.cz/development/input/
S: Maintained
USB HUB DRIVER
...
...
drivers/Makefile
View file @
73df7566
...
...
@@ -15,6 +15,9 @@ obj-$(CONFIG_PNP) += pnp/
# char/ comes before serial/ etc so that the VT console is the boot-time
# default.
obj-y
+=
char/
# we also need input/serio early so serio bus is initialized by the time
# serial drivers start registering their serio ports
obj-$(CONFIG_SERIO)
+=
input/serio/
obj-y
+=
serial/
obj-$(CONFIG_PARPORT)
+=
parport/
obj-y
+=
base/ block/ misc/ net/ media/
...
...
@@ -39,7 +42,6 @@ obj-$(CONFIG_USB) += usb/
obj-$(CONFIG_USB_GADGET)
+=
usb/gadget/
obj-$(CONFIG_INPUT)
+=
input/
obj-$(CONFIG_GAMEPORT)
+=
input/gameport/
obj-$(CONFIG_SERIO)
+=
input/serio/
obj-$(CONFIG_I2O)
+=
message/
obj-$(CONFIG_I2C)
+=
i2c/
obj-$(CONFIG_W1)
+=
w1/
...
...
drivers/char/keyboard.c
View file @
73df7566
...
...
@@ -123,7 +123,7 @@ int shift_state = 0;
*/
static
struct
input_handler
kbd_handler
;
static
unsigned
long
key_down
[
256
/
BITS_PER_LONG
];
/* keyboard key bitmap */
static
unsigned
long
key_down
[
NBITS
(
KEY_MAX
)];
/* keyboard key bitmap */
static
unsigned
char
shift_down
[
NR_SHIFT
];
/* shift state counters.. */
static
int
dead_key_next
;
static
int
npadch
=
-
1
;
/* -1 or number assembled on pad */
...
...
@@ -142,7 +142,7 @@ static struct ledptr {
/* Simple translation table for the SysRq keys */
#ifdef CONFIG_MAGIC_SYSRQ
unsigned
char
kbd_sysrq_xlate
[
128
]
=
unsigned
char
kbd_sysrq_xlate
[
KEY_MAX
]
=
"
\000\033
1234567890-=
\177\t
"
/* 0x00 - 0x0f */
"qwertyuiop[]
\r\000
as"
/* 0x10 - 0x1f */
"dfghjkl;'`
\000\\
zxcv"
/* 0x20 - 0x2f */
...
...
@@ -941,6 +941,9 @@ void kbd_refresh_leds(struct input_handle *handle)
#if defined(CONFIG_X86) || defined(CONFIG_IA64) || defined(CONFIG_ALPHA) || defined(CONFIG_MIPS) || defined(CONFIG_PPC) || defined(CONFIG_SPARC32) || defined(CONFIG_SPARC64) || defined(CONFIG_PARISC) || defined(CONFIG_SUPERH)
#define HW_RAW(dev) (test_bit(EV_MSC, dev->evbit) && test_bit(MSC_RAW, dev->mscbit) &&\
((dev)->id.bustype == BUS_I8042) && ((dev)->id.vendor == 0x0001) && ((dev)->id.product == 0x0001))
static
unsigned
short
x86_keycodes
[
256
]
=
{
0
,
1
,
2
,
3
,
4
,
5
,
6
,
7
,
8
,
9
,
10
,
11
,
12
,
13
,
14
,
15
,
16
,
17
,
18
,
19
,
20
,
21
,
22
,
23
,
24
,
25
,
26
,
27
,
28
,
29
,
30
,
31
,
...
...
@@ -1007,6 +1010,8 @@ static int emulate_raw(struct vc_data *vc, unsigned int keycode,
#else
#define HW_RAW(dev) 0
#warning "Cannot generate rawmode keyboard for your architecture yet."
static
int
emulate_raw
(
struct
vc_data
*
vc
,
unsigned
int
keycode
,
unsigned
char
up_flag
)
...
...
@@ -1019,7 +1024,15 @@ static int emulate_raw(struct vc_data *vc, unsigned int keycode, unsigned char u
}
#endif
void
kbd_keycode
(
unsigned
int
keycode
,
int
down
,
struct
pt_regs
*
regs
)
void
kbd_rawcode
(
unsigned
char
data
)
{
struct
vc_data
*
vc
=
vc_cons
[
fg_console
].
d
;
kbd
=
kbd_table
+
fg_console
;
if
(
kbd
->
kbdmode
==
VC_RAW
)
put_queue
(
vc
,
data
);
}
void
kbd_keycode
(
unsigned
int
keycode
,
int
down
,
int
hw_raw
,
struct
pt_regs
*
regs
)
{
struct
vc_data
*
vc
=
vc_cons
[
fg_console
].
d
;
unsigned
short
keysym
,
*
key_map
;
...
...
@@ -1053,7 +1066,7 @@ void kbd_keycode(unsigned int keycode, int down, struct pt_regs *regs)
return
;
#endif
/* CONFIG_MAC_EMUMOUSEBTN */
if
((
raw_mode
=
(
kbd
->
kbdmode
==
VC_RAW
)))
if
((
raw_mode
=
(
kbd
->
kbdmode
==
VC_RAW
))
&&
!
hw_raw
)
if
(
emulate_raw
(
vc
,
keycode
,
!
down
<<
7
))
if
(
keycode
<
BTN_MISC
)
printk
(
KERN_WARNING
"keyboard.c: can't emulate rawmode for keycode %d
\n
"
,
keycode
);
...
...
@@ -1119,6 +1132,9 @@ void kbd_keycode(unsigned int keycode, int down, struct pt_regs *regs)
return
;
}
if
(
keycode
>
NR_KEYS
)
return
;
keysym
=
key_map
[
keycode
];
type
=
KTYP
(
keysym
);
...
...
@@ -1148,11 +1164,12 @@ void kbd_keycode(unsigned int keycode, int down, struct pt_regs *regs)
}
static
void
kbd_event
(
struct
input_handle
*
handle
,
unsigned
int
event_type
,
unsigned
int
keycode
,
int
down
)
unsigned
int
event_code
,
int
value
)
{
if
(
event_type
!=
EV_KEY
)
return
;
kbd_keycode
(
keycode
,
down
,
handle
->
dev
->
regs
);
if
(
event_type
==
EV_MSC
&&
event_code
==
MSC_RAW
&&
HW_RAW
(
handle
->
dev
))
kbd_rawcode
(
value
);
if
(
event_type
==
EV_KEY
)
kbd_keycode
(
event_code
,
value
,
HW_RAW
(
handle
->
dev
),
handle
->
dev
->
regs
);
tasklet_schedule
(
&
keyboard_tasklet
);
do_poke_blanked_console
=
1
;
schedule_console_callback
();
...
...
drivers/input/gameport/emu10k1-gp.c
View file @
73df7566
...
...
@@ -50,8 +50,11 @@ struct emu {
};
static
struct
pci_device_id
emu_tbl
[]
=
{
{
0x1102
,
0x7002
,
PCI_ANY_ID
,
PCI_ANY_ID
},
/* SB Live gameport */
{
0x1102
,
0x7003
,
PCI_ANY_ID
,
PCI_ANY_ID
},
/* Audigy gameport */
{
0x1102
,
0x7004
,
PCI_ANY_ID
,
PCI_ANY_ID
},
/* Dell SB Live */
{
0x1102
,
0x7005
,
PCI_ANY_ID
,
PCI_ANY_ID
},
/* Audigy LS gameport */
{
0
,
}
};
...
...
drivers/input/joydev.c
View file @
73df7566
...
...
@@ -232,8 +232,10 @@ static ssize_t joydev_read(struct file *file, char __user *buf, size_t count, lo
&&
list
->
head
==
list
->
tail
&&
(
file
->
f_flags
&
O_NONBLOCK
))
return
-
EAGAIN
;
retval
=
wait_event_interruptible
(
list
->
joydev
->
wait
,
list
->
joydev
->
exist
&&
(
list
->
startup
<
joydev
->
nabs
+
joydev
->
nkey
||
list
->
head
!=
list
->
tail
));
retval
=
wait_event_interruptible
(
list
->
joydev
->
wait
,
!
list
->
joydev
->
exist
||
list
->
startup
<
joydev
->
nabs
+
joydev
->
nkey
||
list
->
head
!=
list
->
tail
);
if
(
retval
)
return
retval
;
...
...
drivers/input/joystick/Kconfig
View file @
73df7566
...
...
@@ -247,7 +247,7 @@ config JOYSTICK_AMIGA
To compile this driver as a module, choose M here: the
module will be called amijoy.
config
INPUT
_JOYDUMP
config
JOYSTICK
_JOYDUMP
tristate "Gameport data dumper"
depends on INPUT && INPUT_JOYSTICK
help
...
...
drivers/input/joystick/gamecon.c
View file @
73df7566
/*
*
$Id: gamecon.c,v 1.22 2002/07/01 15:42:25 vojtech Exp $
*
NES, SNES, N64, MultiSystem, PSX gamepad driver for Linux
*
* Copyright (c) 1999-2001 Vojtech Pavlik
* Copyright (c) 1999-2004 Vojtech Pavlik <vojtech@suse.cz>
* Copyright (c) 2004 Peter Nelson <rufus-kernel@hackish.org>
*
* Based on the work of:
* Andree Borrmann John Dahlstrom
* David Kuder Nathan Hand
*/
/*
* NES, SNES, N64, MultiSystem, PSX gamepad driver for Linux
*/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
...
...
@@ -72,8 +69,9 @@ __obsolete_setup("gc_3=");
#define GC_MULTI2 5
#define GC_N64 6
#define GC_PSX 7
#define GC_DDR 8
#define GC_MAX
7
#define GC_MAX
8
#define GC_REFRESH_TIME HZ/100
...
...
@@ -91,7 +89,8 @@ static struct gc *gc_base[3];
static
int
gc_status_bit
[]
=
{
0x40
,
0x80
,
0x20
,
0x10
,
0x08
};
static
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"
};
/*
* N64 support.
*/
...
...
@@ -237,7 +236,7 @@ static void gc_multi_read_packet(struct gc *gc, int length, unsigned char *data)
#define GC_PSX_RUMBLE 7
/* Rumble in Red mode */
#define GC_PSX_CLOCK 0x04
/* Pin 4 */
#define GC_PSX_COMMAND 0x01
/* Pin
1
*/
#define GC_PSX_COMMAND 0x01
/* Pin
2
*/
#define GC_PSX_POWER 0xf8
/* Pins 5-9 */
#define GC_PSX_SELECT 0x02
/* Pin 3 */
...
...
@@ -253,25 +252,29 @@ __obsolete_setup("gc_psx_delay=");
static
short
gc_psx_abs
[]
=
{
ABS_X
,
ABS_Y
,
ABS_RX
,
ABS_RY
,
ABS_HAT0X
,
ABS_HAT0Y
};
static
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
short
gc_psx_ddr_btn
[]
=
{
BTN_0
,
BTN_1
,
BTN_2
,
BTN_3
};
/*
* gc_psx_command() writes 8bit command and reads 8bit data from
* the psx pad.
*/
static
int
gc_psx_command
(
struct
gc
*
gc
,
int
b
)
static
void
gc_psx_command
(
struct
gc
*
gc
,
int
b
,
unsigned
char
data
[
GC_PSX_LENGTH
]
)
{
int
i
,
cmd
,
data
=
0
;
int
i
,
j
,
cmd
,
read
;
for
(
i
=
0
;
i
<
5
;
i
++
)
data
[
i
]
=
0
;
for
(
i
=
0
;
i
<
8
;
i
++
,
b
>>=
1
)
{
cmd
=
(
b
&
1
)
?
GC_PSX_COMMAND
:
0
;
parport_write_data
(
gc
->
pd
->
port
,
cmd
|
GC_PSX_POWER
);
udelay
(
gc_psx_delay
);
data
|=
((
parport_read_status
(
gc
->
pd
->
port
)
^
0x80
)
&
gc
->
pads
[
GC_PSX
])
?
(
1
<<
i
)
:
0
;
read
=
parport_read_status
(
gc
->
pd
->
port
)
^
0x80
;
for
(
j
=
0
;
j
<
5
;
j
++
)
data
[
j
]
|=
(
read
&
gc_status_bit
[
j
]
&
gc
->
pads
[
GC_PSX
])
?
(
1
<<
i
)
:
0
;
parport_write_data
(
gc
->
pd
->
port
,
cmd
|
GC_PSX_CLOCK
|
GC_PSX_POWER
);
udelay
(
gc_psx_delay
);
}
return
data
;
}
/*
...
...
@@ -279,30 +282,39 @@ static int gc_psx_command(struct gc *gc, int b)
* device identifier code.
*/
static
int
gc_psx_read_packet
(
struct
gc
*
gc
,
unsigned
char
*
data
)
static
void
gc_psx_read_packet
(
struct
gc
*
gc
,
unsigned
char
data
[
5
][
GC_PSX_LENGTH
],
unsigned
char
id
[
5
]
)
{
int
i
,
id
;
int
i
,
j
,
max_len
=
0
;
unsigned
long
flags
;
unsigned
char
data2
[
5
];
parport_write_data
(
gc
->
pd
->
port
,
GC_PSX_CLOCK
|
GC_PSX_SELECT
|
GC_PSX_POWER
);
/* Select pad */
udelay
(
gc_psx_delay
*
2
);
udelay
(
gc_psx_delay
);
parport_write_data
(
gc
->
pd
->
port
,
GC_PSX_CLOCK
|
GC_PSX_POWER
);
/* Deselect, begin command */
udelay
(
gc_psx_delay
*
2
);
udelay
(
gc_psx_delay
);
local_irq_save
(
flags
);
gc_psx_command
(
gc
,
0x01
);
/* Access pad */
id
=
gc_psx_command
(
gc
,
0x42
);
/* Get device id */
if
(
gc_psx_command
(
gc
,
0
)
==
0x5a
)
{
/* Okay? */
for
(
i
=
0
;
i
<
GC_PSX_LEN
(
id
)
*
2
;
i
++
)
data
[
i
]
=
gc_psx_command
(
gc
,
0
);
}
else
id
=
0
;
gc_psx_command
(
gc
,
0x01
,
data2
);
/* Access pad */
gc_psx_command
(
gc
,
0x42
,
id
);
/* Get device ids */
gc_psx_command
(
gc
,
0
,
data2
);
/* Dump status */
for
(
i
=
0
;
i
<
5
;
i
++
)
/* Find the longest pad */
if
((
gc_status_bit
[
i
]
&
gc
->
pads
[
GC_PSX
])
&&
(
GC_PSX_LEN
(
id
[
i
])
>
max_len
))
max_len
=
GC_PSX_LEN
(
id
[
i
]);
for
(
i
=
0
;
i
<
max_len
*
2
;
i
++
)
{
/* Read in all the data */
gc_psx_command
(
gc
,
0
,
data2
);
for
(
j
=
0
;
j
<
5
;
j
++
)
data
[
j
][
i
]
=
data2
[
j
];
}
local_irq_restore
(
flags
);
parport_write_data
(
gc
->
pd
->
port
,
GC_PSX_CLOCK
|
GC_PSX_SELECT
|
GC_PSX_POWER
);
return
GC_PSX_ID
(
id
);
for
(
i
=
0
;
i
<
5
;
i
++
)
/* Set id's to the real value */
id
[
i
]
=
GC_PSX_ID
(
id
[
i
]);
}
/*
...
...
@@ -316,6 +328,7 @@ static void gc_timer(unsigned long private)
struct
gc
*
gc
=
(
void
*
)
private
;
struct
input_dev
*
dev
=
gc
->
dev
;
unsigned
char
data
[
GC_MAX_LENGTH
];
unsigned
char
data_psx
[
5
][
GC_PSX_LENGTH
];
int
i
,
j
,
s
;
/*
...
...
@@ -412,53 +425,72 @@ static void gc_timer(unsigned long private)
* PSX controllers
*/
if
(
gc
->
pads
[
GC_PSX
])
{
if
(
gc
->
pads
[
GC_PSX
]
||
gc
->
pads
[
GC_DDR
]
)
{
for
(
i
=
0
;
i
<
5
;
i
++
)
if
(
gc
->
pads
[
GC_PSX
]
&
gc_status_bit
[
i
])
break
;
gc_psx_read_packet
(
gc
,
data_psx
,
data
);
switch
(
gc_psx_read_packet
(
gc
,
data
))
{
for
(
i
=
0
;
i
<
5
;
i
++
)
{
switch
(
data
[
i
])
{
case
GC_PSX_RUMBLE
:
case
GC_PSX_RUMBLE
:
input_report_key
(
dev
+
i
,
BTN_THUMBL
,
~
data
[
0
]
&
0x04
);
input_report_key
(
dev
+
i
,
BTN_THUMBR
,
~
data
[
0
]
&
0x02
);
input_sync
(
dev
+
i
);
input_report_key
(
dev
+
i
,
BTN_THUMBL
,
~
data_psx
[
i
][
0
]
&
0x04
);
input_report_key
(
dev
+
i
,
BTN_THUMBR
,
~
data_psx
[
i
][
0
]
&
0x02
);
case
GC_PSX_NEGCON
:
case
GC_PSX_ANALOG
:
case
GC_PSX_NEGCON
:
case
GC_PSX_ANALOG
:
for
(
j
=
0
;
j
<
4
;
j
++
)
input_report_abs
(
dev
+
i
,
gc_psx_abs
[
j
],
data
[
j
+
2
]);
if
(
gc
->
pads
[
GC_DDR
]
&
gc_status_bit
[
i
])
{
for
(
j
=
0
;
j
<
4
;
j
++
)
input_report_key
(
dev
+
i
,
gc_psx_ddr_btn
[
j
],
~
data_psx
[
i
][
0
]
&
(
0x10
<<
j
));
}
else
{
for
(
j
=
0
;
j
<
4
;
j
++
)
input_report_abs
(
dev
+
i
,
gc_psx_abs
[
j
+
2
],
data_psx
[
i
][
j
+
2
]);
input_report_abs
(
dev
+
i
,
ABS_HAT0X
,
!
(
data
[
0
]
&
0x20
)
-
!
(
data
[
0
]
&
0x80
));
input_report_abs
(
dev
+
i
,
ABS_HAT0Y
,
!
(
data
[
0
]
&
0x40
)
-
!
(
data
[
0
]
&
0x10
));
input_report_abs
(
dev
+
i
,
ABS_X
,
128
+
!
(
data_psx
[
i
][
0
]
&
0x20
)
*
127
-
!
(
data_psx
[
i
][
0
]
&
0x80
)
*
128
);
input_report_abs
(
dev
+
i
,
ABS_Y
,
128
+
!
(
data_psx
[
i
][
0
]
&
0x40
)
*
127
-
!
(
data_psx
[
i
][
0
]
&
0x10
)
*
128
);
}
for
(
j
=
0
;
j
<
8
;
j
++
)
input_report_key
(
dev
+
i
,
gc_psx_btn
[
j
],
~
data
[
1
]
&
(
1
<<
j
));
for
(
j
=
0
;
j
<
8
;
j
++
)
input_report_key
(
dev
+
i
,
gc_psx_btn
[
j
],
~
data_psx
[
i
]
[
1
]
&
(
1
<<
j
));
input_report_key
(
dev
+
i
,
BTN_START
,
~
data
[
0
]
&
0x08
);
input_report_key
(
dev
+
i
,
BTN_SELECT
,
~
data
[
0
]
&
0x01
);
input_report_key
(
dev
+
i
,
BTN_START
,
~
data_psx
[
i
]
[
0
]
&
0x08
);
input_report_key
(
dev
+
i
,
BTN_SELECT
,
~
data_psx
[
i
]
[
0
]
&
0x01
);
input_sync
(
dev
+
i
);
input_sync
(
dev
+
i
);
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
+
i
,
gc_psx_ddr_btn
[
j
],
~
data_psx
[
i
][
0
]
&
(
0x10
<<
j
));
}
else
{
input_report_abs
(
dev
+
i
,
ABS_X
,
128
+
!
(
data_psx
[
i
][
0
]
&
0x20
)
*
127
-
!
(
data_psx
[
i
][
0
]
&
0x80
)
*
128
);
input_report_abs
(
dev
+
i
,
ABS_Y
,
128
+
!
(
data_psx
[
i
][
0
]
&
0x40
)
*
127
-
!
(
data_psx
[
i
][
0
]
&
0x10
)
*
128
);
input_report_abs
(
dev
+
i
,
ABS_X
,
128
+
!
(
data
[
0
]
&
0x20
)
*
127
-
!
(
data
[
0
]
&
0x80
)
*
128
);
input_report_abs
(
dev
+
i
,
ABS_Y
,
128
+
!
(
data
[
0
]
&
0x40
)
*
127
-
!
(
data
[
0
]
&
0x10
)
*
128
);
/* for some reason if the extra axes are left unset they drift */
/* for (j = 0; j < 4; j++)
input_report_abs(dev + i, gc_psx_abs[j+2], 128);
* This needs to be debugged properly,
* maybe fuzz processing needs to be done in input_sync()
* --vojtech
*/
}
for
(
j
=
0
;
j
<
8
;
j
++
)
input_report_key
(
dev
+
i
,
gc_psx_btn
[
j
],
~
data
[
1
]
&
(
1
<<
j
));
for
(
j
=
0
;
j
<
8
;
j
++
)
input_report_key
(
dev
+
i
,
gc_psx_btn
[
j
],
~
data_psx
[
i
]
[
1
]
&
(
1
<<
j
));
input_report_key
(
dev
+
i
,
BTN_START
,
~
data
[
0
]
&
0x08
);
input_report_key
(
dev
+
i
,
BTN_SELECT
,
~
data
[
0
]
&
0x01
);
input_report_key
(
dev
+
i
,
BTN_START
,
~
data_psx
[
i
]
[
0
]
&
0x08
);
input_report_key
(
dev
+
i
,
BTN_SELECT
,
~
data_psx
[
i
]
[
0
]
&
0x01
);
input_sync
(
dev
+
i
);
input_sync
(
dev
+
i
);
break
;
break
;
case
0
:
/* not a pad, ignore */
break
;
}
}
}
...
...
@@ -490,8 +522,7 @@ static struct gc __init *gc_probe(int *config, int nargs)
{
struct
gc
*
gc
;
struct
parport
*
pp
;
int
i
,
j
,
psx
;
unsigned
char
data
[
32
];
int
i
,
j
;
if
(
config
[
0
]
<
0
)
return
NULL
;
...
...
@@ -588,43 +619,22 @@ static struct gc __init *gc_probe(int *config, int nargs)
break
;
case
GC_PSX
:
psx
=
gc_psx_read_packet
(
gc
,
data
);
switch
(
psx
)
{
case
GC_PSX_NEGCON
:
case
GC_PSX_NORMAL
:
case
GC_PSX_ANALOG
:
case
GC_PSX_RUMBLE
:
for
(
j
=
0
;
j
<
6
;
j
++
)
{
psx
=
gc_psx_abs
[
j
];
set_bit
(
psx
,
gc
->
dev
[
i
].
absbit
);
if
(
j
<
4
)
{
gc
->
dev
[
i
].
absmin
[
psx
]
=
4
;
gc
->
dev
[
i
].
absmax
[
psx
]
=
252
;
gc
->
dev
[
i
].
absflat
[
psx
]
=
2
;
}
else
{
gc
->
dev
[
i
].
absmin
[
psx
]
=
-
1
;
gc
->
dev
[
i
].
absmax
[
psx
]
=
1
;
}
}
for
(
j
=
0
;
j
<
12
;
j
++
)
set_bit
(
gc_psx_btn
[
j
],
gc
->
dev
[
i
].
keybit
);
break
;
case
0
:
gc
->
pads
[
GC_PSX
]
&=
~
gc_status_bit
[
i
];
printk
(
KERN_ERR
"gamecon.c: No PSX controller found.
\n
"
);
break
;
default:
gc
->
pads
[
GC_PSX
]
&=
~
gc_status_bit
[
i
];
printk
(
KERN_WARNING
"gamecon.c: Unsupported PSX controller %#x,"
" please report to <vojtech@ucw.cz>.
\n
"
,
psx
);
case
GC_DDR
:
if
(
config
[
i
+
1
]
==
GC_DDR
)
{
for
(
j
=
0
;
j
<
4
;
j
++
)
set_bit
(
gc_psx_ddr_btn
[
j
],
gc
->
dev
[
i
].
keybit
);
}
else
{
for
(
j
=
0
;
j
<
6
;
j
++
)
{
set_bit
(
gc_psx_abs
[
j
],
gc
->
dev
[
i
].
absbit
);
gc
->
dev
[
i
].
absmin
[
gc_psx_abs
[
j
]]
=
4
;
gc
->
dev
[
i
].
absmax
[
gc_psx_abs
[
j
]]
=
252
;
gc
->
dev
[
i
].
absflat
[
gc_psx_abs
[
j
]]
=
2
;
}
}
for
(
j
=
0
;
j
<
12
;
j
++
)
set_bit
(
gc_psx_btn
[
j
],
gc
->
dev
[
i
].
keybit
);
break
;
}
...
...
drivers/input/joystick/iforce/iforce-main.c
View file @
73df7566
...
...
@@ -524,7 +524,7 @@ static int __init iforce_init(void)
usb_register
(
&
iforce_usb_driver
);
#endif
#ifdef CONFIG_JOYSTICK_IFORCE_232
serio_register_d
evice
(
&
iforce_serio_de
v
);
serio_register_d
river
(
&
iforce_serio_dr
v
);
#endif
return
0
;
}
...
...
@@ -535,7 +535,7 @@ static void __exit iforce_exit(void)
usb_deregister
(
&
iforce_usb_driver
);
#endif
#ifdef CONFIG_JOYSTICK_IFORCE_232
serio_unregister_d
evice
(
&
iforce_serio_de
v
);
serio_unregister_d
river
(
&
iforce_serio_dr
v
);
#endif
}
...
...
drivers/input/joystick/iforce/iforce-serio.c
View file @
73df7566
...
...
@@ -124,7 +124,7 @@ static irqreturn_t iforce_serio_irq(struct serio *serio,
return
IRQ_HANDLED
;
}
static
void
iforce_serio_connect
(
struct
serio
*
serio
,
struct
serio_d
ev
*
de
v
)
static
void
iforce_serio_connect
(
struct
serio
*
serio
,
struct
serio_d
river
*
dr
v
)
{
struct
iforce
*
iforce
;
if
(
serio
->
type
!=
(
SERIO_RS232
|
SERIO_IFORCE
))
...
...
@@ -137,7 +137,7 @@ static void iforce_serio_connect(struct serio *serio, struct serio_dev *dev)
iforce
->
serio
=
serio
;
serio
->
private
=
iforce
;
if
(
serio_open
(
serio
,
d
e
v
))
{
if
(
serio_open
(
serio
,
d
r
v
))
{
kfree
(
iforce
);
return
;
}
...
...
@@ -158,9 +158,13 @@ static void iforce_serio_disconnect(struct serio *serio)
kfree
(
iforce
);
}
struct
serio_dev
iforce_serio_dev
=
{
.
write_wakeup
=
iforce_serio_write_wakeup
,
.
interrupt
=
iforce_serio_irq
,
.
connect
=
iforce_serio_connect
,
.
disconnect
=
iforce_serio_disconnect
,
struct
serio_driver
iforce_serio_drv
=
{
.
driver
=
{
.
name
=
"iforce"
,
},
.
description
=
"RS232 I-Force joysticks and wheels driver"
,
.
write_wakeup
=
iforce_serio_write_wakeup
,
.
interrupt
=
iforce_serio_irq
,
.
connect
=
iforce_serio_connect
,
.
disconnect
=
iforce_serio_disconnect
,
};
drivers/input/joystick/iforce/iforce.h
View file @
73df7566
...
...
@@ -187,5 +187,5 @@ int iforce_upload_constant(struct iforce*, struct ff_effect*, int is_update);
int
iforce_upload_condition
(
struct
iforce
*
,
struct
ff_effect
*
,
int
is_update
);
/* Public variables */
extern
struct
serio_d
ev
iforce_serio_de
v
;
extern
struct
serio_d
river
iforce_serio_dr
v
;
extern
struct
usb_driver
iforce_usb_driver
;
drivers/input/joystick/magellan.c
View file @
73df7566
...
...
@@ -35,8 +35,10 @@
#include <linux/serio.h>
#include <linux/init.h>
#define DRIVER_DESC "Magellan and SpaceMouse 6dof controller driver"
MODULE_AUTHOR
(
"Vojtech Pavlik <vojtech@ucw.cz>"
);
MODULE_DESCRIPTION
(
"Magellan and SpaceMouse 6dof controller driver"
);
MODULE_DESCRIPTION
(
DRIVER_DESC
);
MODULE_LICENSE
(
"GPL"
);
/*
...
...
@@ -146,7 +148,7 @@ static void magellan_disconnect(struct serio *serio)
* it as an input device.
*/
static
void
magellan_connect
(
struct
serio
*
serio
,
struct
serio_d
ev
*
de
v
)
static
void
magellan_connect
(
struct
serio
*
serio
,
struct
serio_d
river
*
dr
v
)
{
struct
magellan
*
magellan
;
int
i
,
t
;
...
...
@@ -184,7 +186,7 @@ static void magellan_connect(struct serio *serio, struct serio_dev *dev)
serio
->
private
=
magellan
;
if
(
serio_open
(
serio
,
d
e
v
))
{
if
(
serio_open
(
serio
,
d
r
v
))
{
kfree
(
magellan
);
return
;
}
...
...
@@ -199,10 +201,14 @@ static void magellan_connect(struct serio *serio, struct serio_dev *dev)
* The serio device structure.
*/
static
struct
serio_dev
magellan_dev
=
{
.
interrupt
=
magellan_interrupt
,
.
connect
=
magellan_connect
,
.
disconnect
=
magellan_disconnect
,
static
struct
serio_driver
magellan_drv
=
{
.
driver
=
{
.
name
=
"magellan"
,
},
.
description
=
DRIVER_DESC
,
.
interrupt
=
magellan_interrupt
,
.
connect
=
magellan_connect
,
.
disconnect
=
magellan_disconnect
,
};
/*
...
...
@@ -211,13 +217,13 @@ static struct serio_dev magellan_dev = {
int
__init
magellan_init
(
void
)
{
serio_register_d
evice
(
&
magellan_de
v
);
serio_register_d
river
(
&
magellan_dr
v
);
return
0
;
}
void
__exit
magellan_exit
(
void
)
{
serio_unregister_d
evice
(
&
magellan_de
v
);
serio_unregister_d
river
(
&
magellan_dr
v
);
}
module_init
(
magellan_init
);
...
...
drivers/input/joystick/spaceball.c
View file @
73df7566
...
...
@@ -39,8 +39,10 @@
#include <linux/input.h>
#include <linux/serio.h>
#define DRIVER_DESC "SpaceTec SpaceBall 2003/3003/4000 FLX driver"
MODULE_AUTHOR
(
"Vojtech Pavlik <vojtech@ucw.cz>"
);
MODULE_DESCRIPTION
(
"SpaceTec SpaceBall 2003/3003/4000 FLX driver"
);
MODULE_DESCRIPTION
(
DRIVER_DESC
);
MODULE_LICENSE
(
"GPL"
);
/*
...
...
@@ -201,7 +203,7 @@ static void spaceball_disconnect(struct serio *serio)
* it as an input device.
*/
static
void
spaceball_connect
(
struct
serio
*
serio
,
struct
serio_d
ev
*
de
v
)
static
void
spaceball_connect
(
struct
serio
*
serio
,
struct
serio_d
river
*
dr
v
)
{
struct
spaceball
*
spaceball
;
int
i
,
t
,
id
;
...
...
@@ -254,7 +256,7 @@ static void spaceball_connect(struct serio *serio, struct serio_dev *dev)
serio
->
private
=
spaceball
;
if
(
serio_open
(
serio
,
d
e
v
))
{
if
(
serio_open
(
serio
,
d
r
v
))
{
kfree
(
spaceball
);
return
;
}
...
...
@@ -269,10 +271,14 @@ static void spaceball_connect(struct serio *serio, struct serio_dev *dev)
* The serio device structure.
*/
static
struct
serio_dev
spaceball_dev
=
{
.
interrupt
=
spaceball_interrupt
,
.
connect
=
spaceball_connect
,
.
disconnect
=
spaceball_disconnect
,
static
struct
serio_driver
spaceball_drv
=
{
.
driver
=
{
.
name
=
"spaceball"
,
},
.
description
=
DRIVER_DESC
,
.
interrupt
=
spaceball_interrupt
,
.
connect
=
spaceball_connect
,
.
disconnect
=
spaceball_disconnect
,
};
/*
...
...
@@ -281,13 +287,13 @@ static struct serio_dev spaceball_dev = {
int
__init
spaceball_init
(
void
)
{
serio_register_d
evice
(
&
spaceball_de
v
);
serio_register_d
river
(
&
spaceball_dr
v
);
return
0
;
}
void
__exit
spaceball_exit
(
void
)
{
serio_unregister_d
evice
(
&
spaceball_de
v
);
serio_unregister_d
river
(
&
spaceball_dr
v
);
}
module_init
(
spaceball_init
);
...
...
drivers/input/joystick/spaceorb.c
View file @
73df7566
...
...
@@ -38,8 +38,10 @@
#include <linux/input.h>
#include <linux/serio.h>
#define DRIVER_DESC "SpaceTec SpaceOrb 360 and Avenger 6dof controller driver"
MODULE_AUTHOR
(
"Vojtech Pavlik <vojtech@ucw.cz>"
);
MODULE_DESCRIPTION
(
"SpaceTec SpaceOrb 360 and Avenger 6dof controller driver"
);
MODULE_DESCRIPTION
(
DRIVER_DESC
);
MODULE_LICENSE
(
"GPL"
);
/*
...
...
@@ -162,7 +164,7 @@ static void spaceorb_disconnect(struct serio *serio)
* it as an input device.
*/
static
void
spaceorb_connect
(
struct
serio
*
serio
,
struct
serio_d
ev
*
de
v
)
static
void
spaceorb_connect
(
struct
serio
*
serio
,
struct
serio_d
river
*
dr
v
)
{
struct
spaceorb
*
spaceorb
;
int
i
,
t
;
...
...
@@ -201,7 +203,7 @@ static void spaceorb_connect(struct serio *serio, struct serio_dev *dev)
serio
->
private
=
spaceorb
;
if
(
serio_open
(
serio
,
d
e
v
))
{
if
(
serio_open
(
serio
,
d
r
v
))
{
kfree
(
spaceorb
);
return
;
}
...
...
@@ -213,10 +215,14 @@ static void spaceorb_connect(struct serio *serio, struct serio_dev *dev)
* The serio device structure.
*/
static
struct
serio_dev
spaceorb_dev
=
{
.
interrupt
=
spaceorb_interrupt
,
.
connect
=
spaceorb_connect
,
.
disconnect
=
spaceorb_disconnect
,
static
struct
serio_driver
spaceorb_drv
=
{
.
driver
=
{
.
name
=
"spaceorb"
,
},
.
description
=
DRIVER_DESC
,
.
interrupt
=
spaceorb_interrupt
,
.
connect
=
spaceorb_connect
,
.
disconnect
=
spaceorb_disconnect
,
};
/*
...
...
@@ -225,13 +231,13 @@ static struct serio_dev spaceorb_dev = {
int
__init
spaceorb_init
(
void
)
{
serio_register_d
evice
(
&
spaceorb_de
v
);
serio_register_d
river
(
&
spaceorb_dr
v
);
return
0
;
}
void
__exit
spaceorb_exit
(
void
)
{
serio_unregister_d
evice
(
&
spaceorb_de
v
);
serio_unregister_d
river
(
&
spaceorb_dr
v
);
}
module_init
(
spaceorb_init
);
...
...
drivers/input/joystick/stinger.c
View file @
73df7566
...
...
@@ -36,8 +36,10 @@
#include <linux/serio.h>
#include <linux/init.h>
#define DRIVER_DESC "Gravis Stinger gamepad driver"
MODULE_AUTHOR
(
"Vojtech Pavlik <vojtech@ucw.cz>"
);
MODULE_DESCRIPTION
(
"Gravis Stinger gamepad driver"
);
MODULE_DESCRIPTION
(
DRIVER_DESC
);
MODULE_LICENSE
(
"GPL"
);
/*
...
...
@@ -134,7 +136,7 @@ static void stinger_disconnect(struct serio *serio)
* it as an input device.
*/
static
void
stinger_connect
(
struct
serio
*
serio
,
struct
serio_d
ev
*
de
v
)
static
void
stinger_connect
(
struct
serio
*
serio
,
struct
serio_d
river
*
dr
v
)
{
struct
stinger
*
stinger
;
int
i
;
...
...
@@ -172,7 +174,7 @@ static void stinger_connect(struct serio *serio, struct serio_dev *dev)
stinger
->
dev
.
private
=
stinger
;
serio
->
private
=
stinger
;
if
(
serio_open
(
serio
,
d
e
v
))
{
if
(
serio_open
(
serio
,
d
r
v
))
{
kfree
(
stinger
);
return
;
}
...
...
@@ -187,10 +189,14 @@ static void stinger_connect(struct serio *serio, struct serio_dev *dev)
* The serio device structure.
*/
static
struct
serio_dev
stinger_dev
=
{
.
interrupt
=
stinger_interrupt
,
.
connect
=
stinger_connect
,
.
disconnect
=
stinger_disconnect
,
static
struct
serio_driver
stinger_drv
=
{
.
driver
=
{
.
name
=
"stinger"
,
},
.
description
=
DRIVER_DESC
,
.
interrupt
=
stinger_interrupt
,
.
connect
=
stinger_connect
,
.
disconnect
=
stinger_disconnect
,
};
/*
...
...
@@ -199,13 +205,13 @@ static struct serio_dev stinger_dev = {
int
__init
stinger_init
(
void
)
{
serio_register_d
evice
(
&
stinger_de
v
);
serio_register_d
river
(
&
stinger_dr
v
);
return
0
;
}
void
__exit
stinger_exit
(
void
)
{
serio_unregister_d
evice
(
&
stinger_de
v
);
serio_unregister_d
river
(
&
stinger_dr
v
);
}
module_init
(
stinger_init
);
...
...
drivers/input/joystick/tmdc.c
View file @
73df7566
...
...
@@ -322,7 +322,7 @@ static void tmdc_connect(struct gameport *gameport, struct gameport_dev *dev)
tmdc
->
dev
[
j
].
evbit
[
0
]
=
BIT
(
EV_KEY
)
|
BIT
(
EV_ABS
);
for
(
i
=
0
;
i
<
models
[
m
].
abs
&&
i
<
TMDC_ABS
;
i
++
)
{
if
(
tmdc
->
abs
[
i
]
<
0
)
continue
;
if
(
tmdc
->
abs
[
j
][
i
]
<
0
)
continue
;
set_bit
(
tmdc
->
abs
[
j
][
i
],
tmdc
->
dev
[
j
].
absbit
);
tmdc
->
dev
[
j
].
absmin
[
tmdc
->
abs
[
j
][
i
]]
=
8
;
tmdc
->
dev
[
j
].
absmax
[
tmdc
->
abs
[
j
][
i
]]
=
248
;
...
...
drivers/input/joystick/twidjoy.c
View file @
73df7566
...
...
@@ -187,7 +187,7 @@ static void twidjoy_disconnect(struct serio *serio)
* it as an input device.
*/
static
void
twidjoy_connect
(
struct
serio
*
serio
,
struct
serio_d
ev
*
de
v
)
static
void
twidjoy_connect
(
struct
serio
*
serio
,
struct
serio_d
river
*
dr
v
)
{
struct
twidjoy_button_spec
*
bp
;
struct
twidjoy
*
twidjoy
;
...
...
@@ -232,7 +232,7 @@ static void twidjoy_connect(struct serio *serio, struct serio_dev *dev)
twidjoy
->
dev
.
private
=
twidjoy
;
serio
->
private
=
twidjoy
;
if
(
serio_open
(
serio
,
d
e
v
))
{
if
(
serio_open
(
serio
,
d
r
v
))
{
kfree
(
twidjoy
);
return
;
}
...
...
@@ -246,10 +246,14 @@ static void twidjoy_connect(struct serio *serio, struct serio_dev *dev)
* The serio device structure.
*/
static
struct
serio_dev
twidjoy_dev
=
{
.
interrupt
=
twidjoy_interrupt
,
.
connect
=
twidjoy_connect
,
.
disconnect
=
twidjoy_disconnect
,
static
struct
serio_driver
twidjoy_drv
=
{
.
driver
=
{
.
name
=
"twidjoy"
,
},
.
description
=
DRIVER_DESC
,
.
interrupt
=
twidjoy_interrupt
,
.
connect
=
twidjoy_connect
,
.
disconnect
=
twidjoy_disconnect
,
};
/*
...
...
@@ -258,13 +262,13 @@ static struct serio_dev twidjoy_dev = {
int
__init
twidjoy_init
(
void
)
{
serio_register_d
evice
(
&
twidjoy_de
v
);
serio_register_d
river
(
&
twidjoy_dr
v
);
return
0
;
}
void
__exit
twidjoy_exit
(
void
)
{
serio_unregister_d
evice
(
&
twidjoy_de
v
);
serio_unregister_d
river
(
&
twidjoy_dr
v
);
}
module_init
(
twidjoy_init
);
...
...
drivers/input/joystick/warrior.c
View file @
73df7566
...
...
@@ -35,8 +35,10 @@
#include <linux/serio.h>
#include <linux/init.h>
#define DRIVER_DESC "Logitech WingMan Warrior joystick driver"
MODULE_AUTHOR
(
"Vojtech Pavlik <vojtech@ucw.cz>"
);
MODULE_DESCRIPTION
(
"Logitech WingMan Warrior joystick driver"
);
MODULE_DESCRIPTION
(
DRIVER_DESC
);
MODULE_LICENSE
(
"GPL"
);
/*
...
...
@@ -139,7 +141,7 @@ static void warrior_disconnect(struct serio *serio)
* it as an input device.
*/
static
void
warrior_connect
(
struct
serio
*
serio
,
struct
serio_d
ev
*
de
v
)
static
void
warrior_connect
(
struct
serio
*
serio
,
struct
serio_d
river
*
dr
v
)
{
struct
warrior
*
warrior
;
int
i
;
...
...
@@ -185,7 +187,7 @@ static void warrior_connect(struct serio *serio, struct serio_dev *dev)
serio
->
private
=
warrior
;
if
(
serio_open
(
serio
,
d
e
v
))
{
if
(
serio_open
(
serio
,
d
r
v
))
{
kfree
(
warrior
);
return
;
}
...
...
@@ -199,10 +201,14 @@ static void warrior_connect(struct serio *serio, struct serio_dev *dev)
* The serio device structure.
*/
static
struct
serio_dev
warrior_dev
=
{
.
interrupt
=
warrior_interrupt
,
.
connect
=
warrior_connect
,
.
disconnect
=
warrior_disconnect
,
static
struct
serio_driver
warrior_drv
=
{
.
driver
=
{
.
name
=
"warrior"
,
},
.
description
=
DRIVER_DESC
,
.
interrupt
=
warrior_interrupt
,
.
connect
=
warrior_connect
,
.
disconnect
=
warrior_disconnect
,
};
/*
...
...
@@ -211,13 +217,13 @@ static struct serio_dev warrior_dev = {
int
__init
warrior_init
(
void
)
{
serio_register_d
evice
(
&
warrior_de
v
);
serio_register_d
river
(
&
warrior_dr
v
);
return
0
;
}
void
__exit
warrior_exit
(
void
)
{
serio_unregister_d
evice
(
&
warrior_de
v
);
serio_unregister_d
river
(
&
warrior_dr
v
);
}
module_init
(
warrior_init
);
...
...
drivers/input/keyboard/atkbd.c
View file @
73df7566
...
...
@@ -27,8 +27,10 @@
#include <linux/serio.h>
#include <linux/workqueue.h>
#define DRIVER_DESC "AT and PS/2 keyboard driver"
MODULE_AUTHOR
(
"Vojtech Pavlik <vojtech@suse.cz>"
);
MODULE_DESCRIPTION
(
"AT and PS/2 keyboard driver"
);
MODULE_DESCRIPTION
(
DRIVER_DESC
);
MODULE_LICENSE
(
"GPL"
);
static
int
atkbd_set
=
2
;
...
...
@@ -47,6 +49,10 @@ static int atkbd_softrepeat;
module_param_named
(
softrepeat
,
atkbd_softrepeat
,
bool
,
0
);
MODULE_PARM_DESC
(
softrepeat
,
"Use software keyboard repeat"
);
static
int
atkbd_softraw
=
1
;
module_param_named
(
softraw
,
atkbd_softraw
,
bool
,
0
);
MODULE_PARM_DESC
(
softraw
,
"Use software generated rawmode"
);
static
int
atkbd_scroll
;
module_param_named
(
scroll
,
atkbd_scroll
,
bool
,
0
);
MODULE_PARM_DESC
(
scroll
,
"Enable scroll-wheel on MS Office and similar keyboards"
);
...
...
@@ -164,36 +170,64 @@ static unsigned char atkbd_scroll_keys[5][2] = {
{
ATKBD_SCR_CLICK
,
0x60
},
};
#define ATKBD_FLAG_ACK 0
/* Waiting for ACK/NAK */
#define ATKBD_FLAG_CMD 1
/* Waiting for command to finish */
#define ATKBD_FLAG_CMD1 2
/* First byte of command response */
#define ATKBD_FLAG_ENABLED 3
/* Waining for init to finish */
/*
* The atkbd control structure
*/
struct
atkbd
{
unsigned
char
keycode
[
512
];
struct
input_dev
dev
;
struct
serio
*
serio
;
/* Written only during init */
char
name
[
64
];
char
phys
[
32
];
unsigned
short
id
;
struct
serio
*
serio
;
struct
input_dev
dev
;
unsigned
char
set
;
unsigned
int
translated
:
1
;
unsigned
int
extra
:
1
;
unsigned
int
write
:
1
;
unsigned
short
id
;
unsigned
char
keycode
[
512
];
unsigned
char
translated
;
unsigned
char
extra
;
unsigned
char
write
;
/* Protected by FLAG_ACK */
unsigned
char
nak
;
/* Protected by FLAG_CMD */
unsigned
char
cmdbuf
[
4
];
unsigned
char
cmdcnt
;
volatile
signed
char
ack
;
unsigned
char
emul
;
unsigned
int
resend
:
1
;
unsigned
int
release
:
1
;
unsigned
int
bat_xl
:
1
;
unsigned
int
enabled
:
1
;
/* Accessed only from interrupt */
unsigned
char
emul
;
unsigned
char
resend
;
unsigned
char
release
;
unsigned
char
bat_xl
;
unsigned
int
last
;
unsigned
long
time
;
/* Ensures that only one command is executing at a time */
struct
semaphore
cmd_sem
;
/* Used to signal completion from interrupt handler */
wait_queue_head_t
wait
;
/* Flags */
unsigned
long
flags
;
};
/* Work structure to schedule execution of a command */
struct
atkbd_work
{
struct
work_struct
work
;
struct
atkbd
*
atkbd
;
int
command
;
unsigned
char
param
[
0
];
};
static
void
atkbd_report_key
(
struct
input_dev
*
dev
,
struct
pt_regs
*
regs
,
int
code
,
int
value
)
{
input_regs
(
dev
,
regs
);
...
...
@@ -224,7 +258,7 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
#if !defined(__i386__) && !defined (__x86_64__)
if
((
flags
&
(
SERIO_FRAME
|
SERIO_PARITY
))
&&
(
~
flags
&
SERIO_TIMEOUT
)
&&
!
atkbd
->
resend
&&
atkbd
->
write
)
{
printk
(
"atkbd.c: frame/parity error: %02x
\n
"
,
flags
);
printk
(
KERN_WARNING
"atkbd.c: frame/parity error: %02x
\n
"
,
flags
);
serio_write
(
serio
,
ATKBD_CMD_RESEND
);
atkbd
->
resend
=
1
;
goto
out
;
...
...
@@ -234,24 +268,46 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
atkbd
->
resend
=
0
;
#endif
if
(
!
atkbd
->
ack
)
if
(
test_bit
(
ATKBD_FLAG_ACK
,
&
atkbd
->
flags
))
{
switch
(
code
)
{
case
ATKBD_RET_ACK
:
atkbd
->
ack
=
1
;
goto
out
;
atkbd
->
nak
=
0
;
if
(
atkbd
->
cmdcnt
)
{
set_bit
(
ATKBD_FLAG_CMD
,
&
atkbd
->
flags
);
set_bit
(
ATKBD_FLAG_CMD1
,
&
atkbd
->
flags
);
}
clear_bit
(
ATKBD_FLAG_ACK
,
&
atkbd
->
flags
);
wake_up_interruptible
(
&
atkbd
->
wait
);
break
;
case
ATKBD_RET_NAK
:
atkbd
->
ack
=
-
1
;
goto
out
;
atkbd
->
nak
=
1
;
clear_bit
(
ATKBD_FLAG_ACK
,
&
atkbd
->
flags
);
wake_up_interruptible
(
&
atkbd
->
wait
);
break
;
}
goto
out
;
}
if
(
test_bit
(
ATKBD_FLAG_CMD
,
&
atkbd
->
flags
))
{
if
(
atkbd
->
cmdcnt
)
atkbd
->
cmdbuf
[
--
atkbd
->
cmdcnt
]
=
code
;
if
(
atkbd
->
cmdcnt
)
{
atkbd
->
cmdbuf
[
--
atkbd
->
cmdcnt
]
=
code
;
if
(
test_and_clear_bit
(
ATKBD_FLAG_CMD1
,
&
atkbd
->
flags
)
&&
atkbd
->
cmdcnt
)
wake_up_interruptible
(
&
atkbd
->
wait
);
if
(
!
atkbd
->
cmdcnt
)
{
clear_bit
(
ATKBD_FLAG_CMD
,
&
atkbd
->
flags
);
wake_up_interruptible
(
&
atkbd
->
wait
);
}
goto
out
;
}
if
(
!
atkbd
->
enabled
)
if
(
!
test_bit
(
ATKBD_FLAG_ENABLED
,
&
atkbd
->
flags
)
)
goto
out
;
input_event
(
&
atkbd
->
dev
,
EV_MSC
,
MSC_RAW
,
code
);
if
(
atkbd
->
translated
)
{
if
(
atkbd
->
emul
||
...
...
@@ -270,6 +326,7 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
switch
(
code
)
{
case
ATKBD_RET_BAT
:
clear_bit
(
ATKBD_FLAG_ENABLED
,
&
atkbd
->
flags
);
serio_rescan
(
atkbd
->
serio
);
goto
out
;
case
ATKBD_RET_EMUL0
:
...
...
@@ -300,6 +357,9 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
code
|=
(
atkbd
->
set
!=
3
)
?
0x80
:
0x100
;
}
if
(
atkbd
->
keycode
[
code
]
!=
ATKBD_KEY_NULL
)
input_event
(
&
atkbd
->
dev
,
EV_MSC
,
MSC_SCAN
,
code
);
switch
(
atkbd
->
keycode
[
code
])
{
case
ATKBD_KEY_NULL
:
break
;
...
...
@@ -372,83 +432,147 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
* acknowledge. It doesn't handle resends according to the keyboard
* protocol specs, because if these are needed, the keyboard needs
* replacement anyway, and they only make a mess in the protocol.
*
* atkbd_sendbyte() can only be called from a process context
*/
static
int
atkbd_sendbyte
(
struct
atkbd
*
atkbd
,
unsigned
char
byte
)
{
int
timeout
=
20000
;
/* 200 msec */
atkbd
->
ack
=
0
;
#ifdef ATKBD_DEBUG
printk
(
KERN_DEBUG
"atkbd.c: Sent: %02x
\n
"
,
byte
);
#endif
if
(
serio_write
(
atkbd
->
serio
,
byte
))
return
-
1
;
atkbd
->
nak
=
1
;
set_bit
(
ATKBD_FLAG_ACK
,
&
atkbd
->
flags
)
;
while
(
!
atkbd
->
ack
&&
timeout
--
)
udelay
(
10
);
if
(
serio_write
(
atkbd
->
serio
,
byte
)
==
0
)
wait_event_interruptible_timeout
(
atkbd
->
wait
,
!
test_bit
(
ATKBD_FLAG_ACK
,
&
atkbd
->
flags
),
msecs_to_jiffies
(
200
));
return
-
(
atkbd
->
ack
<=
0
);
clear_bit
(
ATKBD_FLAG_ACK
,
&
atkbd
->
flags
);
return
-
atkbd
->
nak
;
}
/*
* atkbd_command() sends a command, and its parameters to the keyboard,
* then waits for the response and puts it in the param array.
*
* atkbd_command() can only be called from a process context
*/
static
int
atkbd_command
(
struct
atkbd
*
atkbd
,
unsigned
char
*
param
,
int
command
)
{
int
timeout
=
500000
;
/* 500 msec */
int
timeout
;
int
send
=
(
command
>>
12
)
&
0xf
;
int
receive
=
(
command
>>
8
)
&
0xf
;
int
rc
=
-
1
;
int
i
;
atkbd
->
cmdcnt
=
receive
;
timeout
=
msecs_to_jiffies
(
command
==
ATKBD_CMD_RESET_BAT
?
4000
:
500
)
;
if
(
command
==
ATKBD_CMD_RESET_BAT
)
timeout
=
2000000
;
/* 2 sec */
down
(
&
atkbd
->
cmd_sem
);
clear_bit
(
ATKBD_FLAG_CMD
,
&
atkbd
->
flags
);
if
(
receive
&&
param
)
for
(
i
=
0
;
i
<
receive
;
i
++
)
atkbd
->
cmdbuf
[(
receive
-
1
)
-
i
]
=
param
[
i
];
atkbd
->
cmdcnt
=
receive
;
if
(
command
&
0xff
)
if
(
atkbd_sendbyte
(
atkbd
,
command
&
0xff
))
return
(
atkbd
->
cmdcnt
=
0
)
-
1
;
goto
out
;
for
(
i
=
0
;
i
<
send
;
i
++
)
if
(
atkbd_sendbyte
(
atkbd
,
param
[
i
]))
return
(
atkbd
->
cmdcnt
=
0
)
-
1
;
while
(
atkbd
->
cmdcnt
&&
timeout
--
)
{
if
(
atkbd
->
cmdcnt
==
1
&&
command
==
ATKBD_CMD_RESET_BAT
&&
timeout
>
100000
)
timeout
=
100000
;
goto
out
;
if
(
atkbd
->
cmdcnt
==
1
&&
command
==
ATKBD_CMD_GETID
&&
atkbd
->
cmdbuf
[
1
]
!=
0xab
&&
atkbd
->
cmdbuf
[
1
]
!=
0xac
)
{
timeout
=
wait_event_interruptible_timeout
(
atkbd
->
wait
,
!
test_bit
(
ATKBD_FLAG_CMD1
,
&
atkbd
->
flags
),
timeout
);
if
(
atkbd
->
cmdcnt
&&
timeout
>
0
)
{
if
(
command
==
ATKBD_CMD_RESET_BAT
&&
jiffies_to_msecs
(
timeout
)
>
100
)
timeout
=
msecs_to_jiffies
(
100
);
if
(
command
==
ATKBD_CMD_GETID
&&
atkbd
->
cmdbuf
[
receive
-
1
]
!=
0xab
&&
atkbd
->
cmdbuf
[
receive
-
1
]
!=
0xac
)
{
/*
* Device behind the port is not a keyboard
* so we don't need to wait for the 2nd byte
* of ID response.
*/
clear_bit
(
ATKBD_FLAG_CMD
,
&
atkbd
->
flags
);
atkbd
->
cmdcnt
=
0
;
break
;
}
udelay
(
1
);
wait_event_interruptible_timeout
(
atkbd
->
wait
,
!
test_bit
(
ATKBD_FLAG_CMD
,
&
atkbd
->
flags
),
timeout
);
}
if
(
param
)
for
(
i
=
0
;
i
<
receive
;
i
++
)
param
[
i
]
=
atkbd
->
cmdbuf
[(
receive
-
1
)
-
i
];
if
(
command
==
ATKBD_CMD_RESET_BAT
&&
atkbd
->
cmdcnt
==
1
)
atkbd
->
cmdcnt
=
0
;
if
(
atkbd
->
cmdcnt
&&
(
command
!=
ATKBD_CMD_RESET_BAT
||
atkbd
->
cmdcnt
!=
1
))
goto
out
;
rc
=
0
;
out:
clear_bit
(
ATKBD_FLAG_CMD
,
&
atkbd
->
flags
);
clear_bit
(
ATKBD_FLAG_CMD1
,
&
atkbd
->
flags
);
up
(
&
atkbd
->
cmd_sem
);
return
rc
;
}
/*
* atkbd_execute_scheduled_command() sends a command, previously scheduled by
* atkbd_schedule_command(), to the keyboard.
*/
static
void
atkbd_execute_scheduled_command
(
void
*
data
)
{
struct
atkbd_work
*
atkbd_work
=
data
;
atkbd_command
(
atkbd_work
->
atkbd
,
atkbd_work
->
param
,
atkbd_work
->
command
);
kfree
(
atkbd_work
);
}
/*
* atkbd_schedule_command() allows to schedule delayed execution of a keyboard
* command and can be used to issue a command from an interrupt or softirq
* context.
*/
static
int
atkbd_schedule_command
(
struct
atkbd
*
atkbd
,
unsigned
char
*
param
,
int
command
)
{
struct
atkbd_work
*
atkbd_work
;
int
send
=
(
command
>>
12
)
&
0xf
;
int
receive
=
(
command
>>
8
)
&
0xf
;
if
(
!
test_bit
(
ATKBD_FLAG_ENABLED
,
&
atkbd
->
flags
))
return
-
1
;
if
(
!
(
atkbd_work
=
kmalloc
(
sizeof
(
struct
atkbd_work
)
+
max
(
send
,
receive
),
GFP_ATOMIC
)))
return
-
1
;
memset
(
atkbd_work
,
0
,
sizeof
(
struct
atkbd_work
));
atkbd_work
->
atkbd
=
atkbd
;
atkbd_work
->
command
=
command
;
memcpy
(
atkbd_work
->
param
,
param
,
send
);
INIT_WORK
(
&
atkbd_work
->
work
,
atkbd_execute_scheduled_command
,
atkbd_work
);
if
(
atkbd
->
cmdcnt
)
{
atkbd
->
cmdcnt
=
0
;
if
(
!
schedule_work
(
&
atkbd_work
->
work
)
)
{
kfree
(
atkbd_work
)
;
return
-
1
;
}
return
0
;
}
/*
* Event callback from the input module. Events that change the state of
* the hardware are processed here.
...
...
@@ -475,7 +599,7 @@ static int atkbd_event(struct input_dev *dev, unsigned int type, unsigned int co
param
[
0
]
=
(
test_bit
(
LED_SCROLLL
,
dev
->
led
)
?
1
:
0
)
|
(
test_bit
(
LED_NUML
,
dev
->
led
)
?
2
:
0
)
|
(
test_bit
(
LED_CAPSL
,
dev
->
led
)
?
4
:
0
);
atkbd_command
(
atkbd
,
param
,
ATKBD_CMD_SETLEDS
);
atkbd_
schedule_
command
(
atkbd
,
param
,
ATKBD_CMD_SETLEDS
);
if
(
atkbd
->
extra
)
{
param
[
0
]
=
0
;
...
...
@@ -484,7 +608,7 @@ static int atkbd_event(struct input_dev *dev, unsigned int type, unsigned int co
|
(
test_bit
(
LED_SUSPEND
,
dev
->
led
)
?
0x04
:
0
)
|
(
test_bit
(
LED_MISC
,
dev
->
led
)
?
0x10
:
0
)
|
(
test_bit
(
LED_MUTE
,
dev
->
led
)
?
0x20
:
0
);
atkbd_command
(
atkbd
,
param
,
ATKBD_CMD_EX_SETLEDS
);
atkbd_
schedule_
command
(
atkbd
,
param
,
ATKBD_CMD_EX_SETLEDS
);
}
return
0
;
...
...
@@ -500,7 +624,7 @@ static int atkbd_event(struct input_dev *dev, unsigned int type, unsigned int co
dev
->
rep
[
REP_PERIOD
]
=
period
[
i
];
dev
->
rep
[
REP_DELAY
]
=
delay
[
j
];
param
[
0
]
=
i
|
(
j
<<
5
);
atkbd_command
(
atkbd
,
param
,
ATKBD_CMD_SETREP
);
atkbd_
schedule_
command
(
atkbd
,
param
,
ATKBD_CMD_SETREP
);
return
0
;
}
...
...
@@ -672,6 +796,11 @@ static void atkbd_cleanup(struct serio *serio)
static
void
atkbd_disconnect
(
struct
serio
*
serio
)
{
struct
atkbd
*
atkbd
=
serio
->
private
;
clear_bit
(
ATKBD_FLAG_ENABLED
,
&
atkbd
->
flags
);
synchronize_kernel
();
flush_scheduled_work
();
input_unregister_device
(
&
atkbd
->
dev
);
serio_close
(
serio
);
kfree
(
atkbd
);
...
...
@@ -684,7 +813,7 @@ static void atkbd_disconnect(struct serio *serio)
* to the input module.
*/
static
void
atkbd_connect
(
struct
serio
*
serio
,
struct
serio_d
ev
*
de
v
)
static
void
atkbd_connect
(
struct
serio
*
serio
,
struct
serio_d
river
*
dr
v
)
{
struct
atkbd
*
atkbd
;
int
i
;
...
...
@@ -693,6 +822,9 @@ static void atkbd_connect(struct serio *serio, struct serio_dev *dev)
return
;
memset
(
atkbd
,
0
,
sizeof
(
struct
atkbd
));
init_MUTEX
(
&
atkbd
->
cmd_sem
);
init_waitqueue_head
(
&
atkbd
->
wait
);
switch
(
serio
->
type
&
SERIO_TYPE
)
{
case
SERIO_8042_XL
:
...
...
@@ -709,17 +841,22 @@ static void atkbd_connect(struct serio *serio, struct serio_dev *dev)
return
;
}
if
(
!
atkbd
->
write
)
atkbd_softrepeat
=
1
;
if
(
atkbd_softrepeat
)
atkbd_softraw
=
1
;
if
(
atkbd
->
write
)
{
atkbd
->
dev
.
evbit
[
0
]
=
BIT
(
EV_KEY
)
|
BIT
(
EV_LED
)
|
BIT
(
EV_REP
);
atkbd
->
dev
.
evbit
[
0
]
=
BIT
(
EV_KEY
)
|
BIT
(
EV_LED
)
|
BIT
(
EV_REP
)
|
BIT
(
EV_MSC
)
;
atkbd
->
dev
.
ledbit
[
0
]
=
BIT
(
LED_NUML
)
|
BIT
(
LED_CAPSL
)
|
BIT
(
LED_SCROLLL
);
}
else
atkbd
->
dev
.
evbit
[
0
]
=
BIT
(
EV_KEY
)
|
BIT
(
EV_REP
);
}
else
atkbd
->
dev
.
evbit
[
0
]
=
BIT
(
EV_KEY
)
|
BIT
(
EV_REP
)
|
BIT
(
EV_MSC
);
atkbd
->
dev
.
mscbit
[
0
]
=
atkbd_softraw
?
BIT
(
MSC_SCAN
)
:
BIT
(
MSC_RAW
)
|
BIT
(
MSC_SCAN
);
if
(
!
atkbd_softrepeat
)
{
atkbd
->
dev
.
rep
[
REP_DELAY
]
=
250
;
atkbd
->
dev
.
rep
[
REP_PERIOD
]
=
33
;
}
}
else
atkbd_softraw
=
1
;
atkbd
->
ack
=
1
;
atkbd
->
serio
=
serio
;
init_input_dev
(
&
atkbd
->
dev
);
...
...
@@ -732,7 +869,7 @@ static void atkbd_connect(struct serio *serio, struct serio_dev *dev)
serio
->
private
=
atkbd
;
if
(
serio_open
(
serio
,
d
e
v
))
{
if
(
serio_open
(
serio
,
d
r
v
))
{
kfree
(
atkbd
);
return
;
}
...
...
@@ -754,8 +891,6 @@ static void atkbd_connect(struct serio *serio, struct serio_dev *dev)
atkbd
->
id
=
0xab00
;
}
atkbd
->
enabled
=
1
;
if
(
atkbd
->
extra
)
{
atkbd
->
dev
.
ledbit
[
0
]
|=
BIT
(
LED_COMPOSE
)
|
BIT
(
LED_SUSPEND
)
|
BIT
(
LED_SLEEP
)
|
BIT
(
LED_MUTE
)
|
BIT
(
LED_MISC
);
sprintf
(
atkbd
->
name
,
"AT Set 2 Extra keyboard"
);
...
...
@@ -797,6 +932,8 @@ static void atkbd_connect(struct serio *serio, struct serio_dev *dev)
input_register_device
(
&
atkbd
->
dev
);
set_bit
(
ATKBD_FLAG_ENABLED
,
&
atkbd
->
flags
);
printk
(
KERN_INFO
"input: %s on %s
\n
"
,
atkbd
->
name
,
serio
->
phys
);
}
...
...
@@ -808,10 +945,10 @@ static void atkbd_connect(struct serio *serio, struct serio_dev *dev)
static
int
atkbd_reconnect
(
struct
serio
*
serio
)
{
struct
atkbd
*
atkbd
=
serio
->
private
;
struct
serio_d
ev
*
dev
=
serio
->
de
v
;
struct
serio_d
river
*
drv
=
serio
->
dr
v
;
unsigned
char
param
[
1
];
if
(
!
d
e
v
)
{
if
(
!
d
r
v
)
{
printk
(
KERN_DEBUG
"atkbd: reconnect request, but serio is disconnected, ignoring...
\n
"
);
return
-
1
;
}
...
...
@@ -832,26 +969,32 @@ static int atkbd_reconnect(struct serio *serio)
return
-
1
;
}
set_bit
(
ATKBD_FLAG_ENABLED
,
&
atkbd
->
flags
);
return
0
;
}
static
struct
serio_dev
atkbd_dev
=
{
.
interrupt
=
atkbd_interrupt
,
.
connect
=
atkbd_connect
,
.
reconnect
=
atkbd_reconnect
,
.
disconnect
=
atkbd_disconnect
,
.
cleanup
=
atkbd_cleanup
,
static
struct
serio_driver
atkbd_drv
=
{
.
driver
=
{
.
name
=
"atkbd"
,
},
.
description
=
DRIVER_DESC
,
.
interrupt
=
atkbd_interrupt
,
.
connect
=
atkbd_connect
,
.
reconnect
=
atkbd_reconnect
,
.
disconnect
=
atkbd_disconnect
,
.
cleanup
=
atkbd_cleanup
,
};
int
__init
atkbd_init
(
void
)
{
serio_register_d
evice
(
&
atkbd_de
v
);
serio_register_d
river
(
&
atkbd_dr
v
);
return
0
;
}
void
__exit
atkbd_exit
(
void
)
{
serio_unregister_d
evice
(
&
atkbd_de
v
);
serio_unregister_d
river
(
&
atkbd_dr
v
);
}
module_init
(
atkbd_init
);
...
...
drivers/input/keyboard/lkkbd.c
View file @
73df7566
...
...
@@ -76,8 +76,10 @@
#include <linux/serio.h>
#include <linux/workqueue.h>
#define DRIVER_DESC "LK keyboard driver"
MODULE_AUTHOR
(
"Jan-Benedict Glaw <jbglaw@lug-owl.de>"
);
MODULE_DESCRIPTION
(
"LK keyboard driver"
);
MODULE_DESCRIPTION
(
DRIVER_DESC
);
MODULE_LICENSE
(
"GPL"
);
/*
...
...
@@ -622,7 +624,7 @@ lkkbd_reinit (void *data)
* lkkbd_connect() probes for a LK keyboard and fills the necessary structures.
*/
static
void
lkkbd_connect
(
struct
serio
*
serio
,
struct
serio_d
ev
*
de
v
)
lkkbd_connect
(
struct
serio
*
serio
,
struct
serio_d
river
*
dr
v
)
{
struct
lkkbd
*
lk
;
int
i
;
...
...
@@ -665,7 +667,7 @@ lkkbd_connect (struct serio *serio, struct serio_dev *dev)
serio
->
private
=
lk
;
if
(
serio_open
(
serio
,
d
e
v
))
{
if
(
serio_open
(
serio
,
d
r
v
))
{
kfree
(
lk
);
return
;
}
...
...
@@ -703,10 +705,14 @@ lkkbd_disconnect (struct serio *serio)
kfree
(
lk
);
}
static
struct
serio_dev
lkkbd_dev
=
{
.
connect
=
lkkbd_connect
,
.
disconnect
=
lkkbd_disconnect
,
.
interrupt
=
lkkbd_interrupt
,
static
struct
serio_driver
lkkbd_drv
=
{
.
driver
=
{
.
name
=
"lkkbd"
,
},
.
description
=
DRIVER_DESC
,
.
connect
=
lkkbd_connect
,
.
disconnect
=
lkkbd_disconnect
,
.
interrupt
=
lkkbd_interrupt
,
};
/*
...
...
@@ -715,14 +721,14 @@ static struct serio_dev lkkbd_dev = {
int
__init
lkkbd_init
(
void
)
{
serio_register_d
evice
(
&
lkkbd_de
v
);
serio_register_d
river
(
&
lkkbd_dr
v
);
return
0
;
}
void
__exit
lkkbd_exit
(
void
)
{
serio_unregister_d
evice
(
&
lkkbd_de
v
);
serio_unregister_d
river
(
&
lkkbd_dr
v
);
}
module_init
(
lkkbd_init
);
...
...
drivers/input/keyboard/newtonkbd.c
View file @
73df7566
...
...
@@ -32,8 +32,10 @@
#include <linux/init.h>
#include <linux/serio.h>
#define DRIVER_DESC "Newton keyboard driver"
MODULE_AUTHOR
(
"Justin Cormack <j.cormack@doc.ic.ac.uk>"
);
MODULE_DESCRIPTION
(
"Newton keyboard driver"
);
MODULE_DESCRIPTION
(
DRIVER_DESC
);
MODULE_LICENSE
(
"GPL"
);
#define NKBD_KEY 0x7f
...
...
@@ -82,7 +84,7 @@ irqreturn_t nkbd_interrupt(struct serio *serio,
}
void
nkbd_connect
(
struct
serio
*
serio
,
struct
serio_d
ev
*
de
v
)
void
nkbd_connect
(
struct
serio
*
serio
,
struct
serio_d
river
*
dr
v
)
{
struct
nkbd
*
nkbd
;
int
i
;
...
...
@@ -106,7 +108,7 @@ void nkbd_connect(struct serio *serio, struct serio_dev *dev)
nkbd
->
dev
.
private
=
nkbd
;
serio
->
private
=
nkbd
;
if
(
serio_open
(
serio
,
d
e
v
))
{
if
(
serio_open
(
serio
,
d
r
v
))
{
kfree
(
nkbd
);
return
;
}
...
...
@@ -138,21 +140,25 @@ void nkbd_disconnect(struct serio *serio)
kfree
(
nkbd
);
}
struct
serio_dev
nkbd_dev
=
{
.
interrupt
=
nkbd_interrupt
,
.
connect
=
nkbd_connect
,
.
disconnect
=
nkbd_disconnect
struct
serio_driver
nkbd_drv
=
{
.
driver
=
{
.
name
=
"newtonkbd"
,
},
.
description
=
DRIVER_DESC
,
.
interrupt
=
nkbd_interrupt
,
.
connect
=
nkbd_connect
,
.
disconnect
=
nkbd_disconnect
,
};
int
__init
nkbd_init
(
void
)
{
serio_register_d
evice
(
&
nkbd_de
v
);
serio_register_d
river
(
&
nkbd_dr
v
);
return
0
;
}
void
__exit
nkbd_exit
(
void
)
{
serio_unregister_d
evice
(
&
nkbd_de
v
);
serio_unregister_d
river
(
&
nkbd_dr
v
);
}
module_init
(
nkbd_init
);
...
...
drivers/input/keyboard/sunkbd.c
View file @
73df7566
...
...
@@ -37,8 +37,10 @@
#include <linux/serio.h>
#include <linux/workqueue.h>
#define DRIVER_DESC "Sun keyboard driver"
MODULE_AUTHOR
(
"Vojtech Pavlik <vojtech@ucw.cz>"
);
MODULE_DESCRIPTION
(
"Sun keyboard driver"
);
MODULE_DESCRIPTION
(
DRIVER_DESC
);
MODULE_LICENSE
(
"GPL"
);
static
unsigned
char
sunkbd_keycode
[
128
]
=
{
...
...
@@ -221,7 +223,7 @@ static void sunkbd_reinit(void *data)
* sunkbd_connect() probes for a Sun keyboard and fills the necessary structures.
*/
static
void
sunkbd_connect
(
struct
serio
*
serio
,
struct
serio_d
ev
*
de
v
)
static
void
sunkbd_connect
(
struct
serio
*
serio
,
struct
serio_d
river
*
dr
v
)
{
struct
sunkbd
*
sunkbd
;
int
i
;
...
...
@@ -257,7 +259,7 @@ static void sunkbd_connect(struct serio *serio, struct serio_dev *dev)
serio
->
private
=
sunkbd
;
if
(
serio_open
(
serio
,
d
e
v
))
{
if
(
serio_open
(
serio
,
d
r
v
))
{
kfree
(
sunkbd
);
return
;
}
...
...
@@ -301,10 +303,14 @@ static void sunkbd_disconnect(struct serio *serio)
kfree
(
sunkbd
);
}
static
struct
serio_dev
sunkbd_dev
=
{
.
interrupt
=
sunkbd_interrupt
,
.
connect
=
sunkbd_connect
,
.
disconnect
=
sunkbd_disconnect
static
struct
serio_driver
sunkbd_drv
=
{
.
driver
=
{
.
name
=
"sunkbd"
,
},
.
description
=
DRIVER_DESC
,
.
interrupt
=
sunkbd_interrupt
,
.
connect
=
sunkbd_connect
,
.
disconnect
=
sunkbd_disconnect
,
};
/*
...
...
@@ -313,13 +319,13 @@ static struct serio_dev sunkbd_dev = {
int
__init
sunkbd_init
(
void
)
{
serio_register_d
evice
(
&
sunkbd_de
v
);
serio_register_d
river
(
&
sunkbd_dr
v
);
return
0
;
}
void
__exit
sunkbd_exit
(
void
)
{
serio_unregister_d
evice
(
&
sunkbd_de
v
);
serio_unregister_d
river
(
&
sunkbd_dr
v
);
}
module_init
(
sunkbd_init
);
...
...
drivers/input/keyboard/xtkbd.c
View file @
73df7566
...
...
@@ -34,8 +34,10 @@
#include <linux/init.h>
#include <linux/serio.h>
#define DRIVER_DESC "XT keyboard driver"
MODULE_AUTHOR
(
"Vojtech Pavlik <vojtech@ucw.cz>"
);
MODULE_DESCRIPTION
(
"XT keyboard driver"
);
MODULE_DESCRIPTION
(
DRIVER_DESC
);
MODULE_LICENSE
(
"GPL"
);
#define XTKBD_EMUL0 0xe0
...
...
@@ -86,7 +88,7 @@ irqreturn_t xtkbd_interrupt(struct serio *serio,
return
IRQ_HANDLED
;
}
void
xtkbd_connect
(
struct
serio
*
serio
,
struct
serio_d
ev
*
de
v
)
void
xtkbd_connect
(
struct
serio
*
serio
,
struct
serio_d
river
*
dr
v
)
{
struct
xtkbd
*
xtkbd
;
int
i
;
...
...
@@ -111,7 +113,7 @@ void xtkbd_connect(struct serio *serio, struct serio_dev *dev)
serio
->
private
=
xtkbd
;
if
(
serio_open
(
serio
,
d
e
v
))
{
if
(
serio_open
(
serio
,
d
r
v
))
{
kfree
(
xtkbd
);
return
;
}
...
...
@@ -143,21 +145,25 @@ void xtkbd_disconnect(struct serio *serio)
kfree
(
xtkbd
);
}
struct
serio_dev
xtkbd_dev
=
{
.
interrupt
=
xtkbd_interrupt
,
.
connect
=
xtkbd_connect
,
.
disconnect
=
xtkbd_disconnect
struct
serio_driver
xtkbd_drv
=
{
.
driver
=
{
.
name
=
"xtkbd"
,
},
.
description
=
DRIVER_DESC
,
.
interrupt
=
xtkbd_interrupt
,
.
connect
=
xtkbd_connect
,
.
disconnect
=
xtkbd_disconnect
,
};
int
__init
xtkbd_init
(
void
)
{
serio_register_d
evice
(
&
xtkbd_de
v
);
serio_register_d
river
(
&
xtkbd_dr
v
);
return
0
;
}
void
__exit
xtkbd_exit
(
void
)
{
serio_unregister_d
evice
(
&
xtkbd_de
v
);
serio_unregister_d
river
(
&
xtkbd_dr
v
);
}
module_init
(
xtkbd_init
);
...
...
drivers/input/misc/Kconfig
View file @
73df7566
...
...
@@ -14,7 +14,7 @@ config INPUT_MISC
config INPUT_PCSPKR
tristate "PC Speaker support"
depends on (ALPHA || X86 || X86_64 || MIPS) && INPUT && INPUT_MISC
depends on (ALPHA || X86 || X86_64 || MIPS
|| PPC_PREP || PPC_CHRP || PPC_PSERIES
) && INPUT && INPUT_MISC
help
Say Y here if you want the standard PC Speaker to be used for
bells and whistles.
...
...
drivers/input/misc/uinput.c
View file @
73df7566
...
...
@@ -279,6 +279,9 @@ static unsigned int uinput_poll(struct file *file, poll_table *wait)
{
struct
uinput_device
*
udev
=
file
->
private_data
;
if
(
!
test_bit
(
UIST_CREATED
,
&
(
udev
->
state
)))
return
0
;
poll_wait
(
file
,
&
udev
->
waitq
,
wait
);
if
(
udev
->
head
!=
udev
->
tail
)
...
...
drivers/input/mouse/Kconfig
View file @
73df7566
...
...
@@ -30,8 +30,6 @@ config MOUSE_PS2
and a new verion of GPM at:
http://www.geocities.com/dt_or/gpm/gpm.html
to take advantage of the advanced features of the touchpad.
If you do not want install specialized drivers but want tapping
working please use option psmouse.proto=imps.
If unsure, say Y.
...
...
drivers/input/mouse/logips2pp.c
View file @
73df7566
...
...
@@ -277,7 +277,7 @@ int ps2pp_init(struct psmouse *psmouse, int set_properties)
protocol
=
PSMOUSE_PS2TPP
;
}
}
else
if
(
get_model_info
(
model
)
!=
NULL
)
{
}
else
if
(
model_info
!=
NULL
)
{
param
[
0
]
=
param
[
1
]
=
param
[
2
]
=
0
;
ps2pp_cmd
(
psmouse
,
param
,
0x39
);
/* Magic knock */
...
...
drivers/input/mouse/psmouse-base.c
View file @
73df7566
...
...
@@ -22,8 +22,10 @@
#include "synaptics.h"
#include "logips2pp.h"
#define DRIVER_DESC "PS/2 mouse driver"
MODULE_AUTHOR
(
"Vojtech Pavlik <vojtech@suse.cz>"
);
MODULE_DESCRIPTION
(
"PS/2 mouse driver"
);
MODULE_DESCRIPTION
(
DRIVER_DESC
);
MODULE_LICENSE
(
"GPL"
);
static
char
*
psmouse_proto
;
...
...
@@ -142,37 +144,67 @@ static irqreturn_t psmouse_interrupt(struct serio *serio,
printk
(
KERN_WARNING
"psmouse.c: bad data from KBC -%s%s
\n
"
,
flags
&
SERIO_TIMEOUT
?
" timeout"
:
""
,
flags
&
SERIO_PARITY
?
" bad parity"
:
""
);
if
(
psmouse
->
acking
)
{
psmouse
->
ack
=
-
1
;
psmouse
->
acking
=
0
;
}
psmouse
->
pktcnt
=
0
;
psmouse
->
nak
=
1
;
clear_bit
(
PSMOUSE_FLAG_ACK
,
&
psmouse
->
flags
);
clear_bit
(
PSMOUSE_FLAG_CMD
,
&
psmouse
->
flags
);
wake_up_interruptible
(
&
psmouse
->
wait
);
goto
out
;
}
if
(
psmouse
->
acking
)
{
if
(
test_bit
(
PSMOUSE_FLAG_ACK
,
&
psmouse
->
flags
)
)
{
switch
(
data
)
{
case
PSMOUSE_RET_ACK
:
psmouse
->
ack
=
1
;
psmouse
->
nak
=
0
;
break
;
case
PSMOUSE_RET_NAK
:
psmouse
->
ack
=
-
1
;
psmouse
->
nak
=
1
;
break
;
/*
* Workaround for mice which don't ACK the Get ID command.
* These are valid mouse IDs that we recognize.
*/
case
0x00
:
case
0x03
:
case
0x04
:
if
(
test_bit
(
PSMOUSE_FLAG_WAITID
,
&
psmouse
->
flags
))
{
psmouse
->
nak
=
0
;
break
;
}
/* Fall through */
default:
psmouse
->
ack
=
1
;
/* Workaround for mice which don't ACK the Get ID command */
if
(
psmouse
->
cmdcnt
)
psmouse
->
cmdbuf
[
--
psmouse
->
cmdcnt
]
=
data
;
break
;
goto
out
;
}
psmouse
->
acking
=
0
;
goto
out
;
if
(
!
psmouse
->
nak
&&
psmouse
->
cmdcnt
)
{
set_bit
(
PSMOUSE_FLAG_CMD
,
&
psmouse
->
flags
);
set_bit
(
PSMOUSE_FLAG_CMD1
,
&
psmouse
->
flags
);
}
clear_bit
(
PSMOUSE_FLAG_ACK
,
&
psmouse
->
flags
);
wake_up_interruptible
(
&
psmouse
->
wait
);
if
(
data
==
PSMOUSE_RET_ACK
||
data
==
PSMOUSE_RET_NAK
)
goto
out
;
}
if
(
psmouse
->
cmdcnt
)
{
psmouse
->
cmdbuf
[
--
psmouse
->
cmdcnt
]
=
data
;
if
(
test_bit
(
PSMOUSE_FLAG_CMD
,
&
psmouse
->
flags
))
{
if
(
psmouse
->
cmdcnt
)
psmouse
->
cmdbuf
[
--
psmouse
->
cmdcnt
]
=
data
;
if
(
test_and_clear_bit
(
PSMOUSE_FLAG_CMD1
,
&
psmouse
->
flags
)
&&
psmouse
->
cmdcnt
)
wake_up_interruptible
(
&
psmouse
->
wait
);
if
(
!
psmouse
->
cmdcnt
)
{
clear_bit
(
PSMOUSE_FLAG_CMD
,
&
psmouse
->
flags
);
wake_up_interruptible
(
&
psmouse
->
wait
);
}
goto
out
;
}
if
(
psmouse
->
state
==
PSMOUSE_INITIALIZING
)
goto
out
;
if
(
psmouse
->
state
==
PSMOUSE_ACTIVATED
&&
psmouse
->
pktcnt
&&
time_after
(
jiffies
,
psmouse
->
last
+
HZ
/
2
))
{
printk
(
KERN_WARNING
"psmouse.c: %s at %s lost synchronization, throwing %d bytes away.
\n
"
,
...
...
@@ -238,78 +270,96 @@ static irqreturn_t psmouse_interrupt(struct serio *serio,
* psmouse_sendbyte() sends a byte to the mouse, and waits for acknowledge.
* It doesn't handle retransmission, though it could - because when there would
* be need for retransmissions, the mouse has to be replaced anyway.
*
* psmouse_sendbyte() can only be called from a process context
*/
static
int
psmouse_sendbyte
(
struct
psmouse
*
psmouse
,
unsigned
char
byte
)
{
int
timeout
=
10000
;
/* 100 msec */
psmouse
->
ack
=
0
;
psmouse
->
acking
=
1
;
if
(
serio_write
(
psmouse
->
serio
,
byte
))
{
psmouse
->
acking
=
0
;
return
-
1
;
}
psmouse
->
nak
=
1
;
set_bit
(
PSMOUSE_FLAG_ACK
,
&
psmouse
->
flags
);
while
(
!
psmouse
->
ack
&&
timeout
--
)
udelay
(
10
);
if
(
serio_write
(
psmouse
->
serio
,
byte
)
==
0
)
wait_event_interruptible_timeout
(
psmouse
->
wait
,
!
test_bit
(
PSMOUSE_FLAG_ACK
,
&
psmouse
->
flags
),
msecs_to_jiffies
(
200
));
return
-
(
psmouse
->
ack
<=
0
);
clear_bit
(
PSMOUSE_FLAG_ACK
,
&
psmouse
->
flags
);
return
-
psmouse
->
nak
;
}
/*
* psmouse_command() sends a command and its parameters to the mouse,
* then waits for the response and puts it in the param array.
*
* psmouse_command() can only be called from a process context
*/
int
psmouse_command
(
struct
psmouse
*
psmouse
,
unsigned
char
*
param
,
int
command
)
{
int
timeout
=
500000
;
/* 500 msec */
int
timeout
;
int
send
=
(
command
>>
12
)
&
0xf
;
int
receive
=
(
command
>>
8
)
&
0xf
;
int
rc
=
-
1
;
int
i
;
psmouse
->
cmdcnt
=
receive
;
timeout
=
msecs_to_jiffies
(
command
==
PSMOUSE_CMD_RESET_BAT
?
4000
:
500
)
;
if
(
command
==
PSMOUSE_CMD_RESET_BAT
)
timeout
=
4000000
;
/* 4 sec */
clear_bit
(
PSMOUSE_FLAG_CMD
,
&
psmouse
->
flags
);
if
(
command
==
PSMOUSE_CMD_GETID
)
set_bit
(
PSMOUSE_FLAG_WAITID
,
&
psmouse
->
flags
);
/* initialize cmdbuf with preset values from param */
if
(
receive
)
for
(
i
=
0
;
i
<
receive
;
i
++
)
psmouse
->
cmdbuf
[(
receive
-
1
)
-
i
]
=
param
[
i
];
if
(
receive
&&
param
)
for
(
i
=
0
;
i
<
receive
;
i
++
)
psmouse
->
cmdbuf
[(
receive
-
1
)
-
i
]
=
param
[
i
];
psmouse
->
cmdcnt
=
receive
;
if
(
command
&
0xff
)
if
(
psmouse_sendbyte
(
psmouse
,
command
&
0xff
))
return
(
psmouse
->
cmdcnt
=
0
)
-
1
;
goto
out
;
for
(
i
=
0
;
i
<
send
;
i
++
)
if
(
psmouse_sendbyte
(
psmouse
,
param
[
i
]))
return
(
psmouse
->
cmdcnt
=
0
)
-
1
;
while
(
psmouse
->
cmdcnt
&&
timeout
--
)
{
if
(
psmouse
->
cmdcnt
==
1
&&
command
==
PSMOUSE_CMD_RESET_BAT
&&
timeout
>
100000
)
/* do not run in a endless loop */
timeout
=
100000
;
/* 1 sec */
goto
out
;
if
(
psmouse
->
cmdcnt
==
1
&&
command
==
PSMOUSE_CMD_GETID
&&
psmouse
->
cmdbuf
[
1
]
!=
0xab
&&
psmouse
->
cmdbuf
[
1
]
!=
0xac
)
{
timeout
=
wait_event_interruptible_timeout
(
psmouse
->
wait
,
!
test_bit
(
PSMOUSE_FLAG_CMD1
,
&
psmouse
->
flags
),
timeout
);
if
(
psmouse
->
cmdcnt
&&
timeout
>
0
)
{
if
(
command
==
PSMOUSE_CMD_RESET_BAT
&&
jiffies_to_msecs
(
timeout
)
>
100
)
timeout
=
msecs_to_jiffies
(
100
);
if
(
command
==
PSMOUSE_CMD_GETID
&&
psmouse
->
cmdbuf
[
receive
-
1
]
!=
0xab
&&
psmouse
->
cmdbuf
[
receive
-
1
]
!=
0xac
)
{
/*
* Device behind the port is not a keyboard
* so we don't need to wait for the 2nd byte
* of ID response.
*/
clear_bit
(
PSMOUSE_FLAG_CMD
,
&
psmouse
->
flags
);
psmouse
->
cmdcnt
=
0
;
break
;
}
udelay
(
1
);
wait_event_interruptible_timeout
(
psmouse
->
wait
,
!
test_bit
(
PSMOUSE_FLAG_CMD
,
&
psmouse
->
flags
),
timeout
);
}
for
(
i
=
0
;
i
<
receive
;
i
++
)
param
[
i
]
=
psmouse
->
cmdbuf
[(
receive
-
1
)
-
i
];
if
(
param
)
for
(
i
=
0
;
i
<
receive
;
i
++
)
param
[
i
]
=
psmouse
->
cmdbuf
[(
receive
-
1
)
-
i
];
if
(
psmouse
->
cmdcnt
)
return
(
psmouse
->
cmdcnt
=
0
)
-
1
;
if
(
psmouse
->
cmdcnt
&&
(
command
!=
PSMOUSE_CMD_RESET_BAT
||
psmouse
->
cmdcnt
!=
1
)
)
goto
out
;
return
0
;
}
rc
=
0
;
out:
clear_bit
(
PSMOUSE_FLAG_CMD
,
&
psmouse
->
flags
);
clear_bit
(
PSMOUSE_FLAG_CMD1
,
&
psmouse
->
flags
);
clear_bit
(
PSMOUSE_FLAG_WAITID
,
&
psmouse
->
flags
);
return
rc
;
}
/*
* psmouse_sliced_command() sends an extended PS/2 command to the mouse
...
...
@@ -394,6 +444,8 @@ static int im_explorer_detect(struct psmouse *psmouse)
{
unsigned
char
param
[
2
];
intellimouse_detect
(
psmouse
);
param
[
0
]
=
200
;
psmouse_command
(
psmouse
,
param
,
PSMOUSE_CMD_SETRATE
);
param
[
0
]
=
200
;
...
...
@@ -597,6 +649,21 @@ static void psmouse_initialize(struct psmouse *psmouse)
psmouse_command
(
psmouse
,
param
,
PSMOUSE_CMD_SETSTREAM
);
}
/*
* psmouse_set_state() sets new psmouse state and resets all flags and
* counters while holding serio lock so fighting with interrupt handler
* is not a concern.
*/
static
void
psmouse_set_state
(
struct
psmouse
*
psmouse
,
enum
psmouse_state
new_state
)
{
serio_pause_rx
(
psmouse
->
serio
);
psmouse
->
state
=
new_state
;
psmouse
->
pktcnt
=
psmouse
->
cmdcnt
=
psmouse
->
out_of_sync
=
0
;
psmouse
->
flags
=
0
;
serio_continue_rx
(
psmouse
->
serio
);
}
/*
* psmouse_activate() enables the mouse so that we get motion reports from it.
*/
...
...
@@ -606,9 +673,24 @@ static void psmouse_activate(struct psmouse *psmouse)
if
(
psmouse_command
(
psmouse
,
NULL
,
PSMOUSE_CMD_ENABLE
))
printk
(
KERN_WARNING
"psmouse.c: Failed to enable mouse on %s
\n
"
,
psmouse
->
serio
->
phys
);
psmouse
->
state
=
PSMOUSE_ACTIVATED
;
psmouse_set_state
(
psmouse
,
PSMOUSE_ACTIVATED
);
}
/*
* psmouse_deactivate() puts the mouse into poll mode so that we don't get motion
* reports from it unless we explicitely request it.
*/
static
void
psmouse_deactivate
(
struct
psmouse
*
psmouse
)
{
if
(
psmouse_command
(
psmouse
,
NULL
,
PSMOUSE_CMD_DISABLE
))
printk
(
KERN_WARNING
"psmouse.c: Failed to deactivate mouse on %s
\n
"
,
psmouse
->
serio
->
phys
);
psmouse_set_state
(
psmouse
,
PSMOUSE_CMD_MODE
);
}
/*
* psmouse_cleanup() resets the mouse into power-on state.
*/
...
...
@@ -626,22 +708,21 @@ static void psmouse_cleanup(struct serio *serio)
static
void
psmouse_disconnect
(
struct
serio
*
serio
)
{
struct
psmouse
*
psmouse
=
serio
->
private
;
struct
psmouse
*
psmouse
,
*
parent
;
psmouse
->
state
=
PSMOUSE_CMD_MODE
;
psmouse
=
serio
->
private
;
psmouse_set_state
(
psmouse
,
PSMOUSE_CMD_MODE
);
if
(
psmouse
->
ptport
)
{
if
(
psmouse
->
ptport
->
deactivate
)
psmouse
->
ptport
->
deactivate
(
psmouse
);
__serio_unregister_port
(
&
psmouse
->
ptport
->
serio
);
/* we have serio_sem */
kfree
(
psmouse
->
ptport
);
psmouse
->
ptport
=
NULL
;
if
(
serio
->
parent
&&
(
serio
->
type
&
SERIO_TYPE
)
==
SERIO_PS_PSTHRU
)
{
parent
=
serio
->
parent
->
private
;
if
(
parent
->
pt_deactivate
)
parent
->
pt_deactivate
(
parent
);
}
if
(
psmouse
->
disconnect
)
psmouse
->
disconnect
(
psmouse
);
psmouse
->
state
=
PSMOUSE_IGNORE
;
psmouse
_set_state
(
psmouse
,
PSMOUSE_IGNORE
)
;
input_unregister_device
(
&
psmouse
->
dev
);
serio_close
(
serio
);
...
...
@@ -652,39 +733,49 @@ static void psmouse_disconnect(struct serio *serio)
* psmouse_connect() is a callback from the serio module when
* an unhandled serio port is found.
*/
static
void
psmouse_connect
(
struct
serio
*
serio
,
struct
serio_d
ev
*
de
v
)
static
void
psmouse_connect
(
struct
serio
*
serio
,
struct
serio_d
river
*
dr
v
)
{
struct
psmouse
*
psmouse
;
struct
psmouse
*
psmouse
,
*
parent
=
NULL
;
if
((
serio
->
type
&
SERIO_TYPE
)
!=
SERIO_8042
&&
(
serio
->
type
&
SERIO_TYPE
)
!=
SERIO_PS_PSTHRU
)
return
;
/*
* If this is a pass-through port deactivate parent so the device
* connected to this port can be successfully identified
*/
if
(
serio
->
parent
&&
(
serio
->
type
&
SERIO_TYPE
)
==
SERIO_PS_PSTHRU
)
{
parent
=
serio
->
parent
->
private
;
psmouse_deactivate
(
parent
);
}
if
(
!
(
psmouse
=
kmalloc
(
sizeof
(
struct
psmouse
),
GFP_KERNEL
)))
return
;
goto
out
;
memset
(
psmouse
,
0
,
sizeof
(
struct
psmouse
));
init_waitqueue_head
(
&
psmouse
->
wait
);
init_input_dev
(
&
psmouse
->
dev
);
psmouse
->
dev
.
evbit
[
0
]
=
BIT
(
EV_KEY
)
|
BIT
(
EV_REL
);
psmouse
->
dev
.
keybit
[
LONG
(
BTN_MOUSE
)]
=
BIT
(
BTN_LEFT
)
|
BIT
(
BTN_MIDDLE
)
|
BIT
(
BTN_RIGHT
);
psmouse
->
dev
.
relbit
[
0
]
=
BIT
(
REL_X
)
|
BIT
(
REL_Y
);
psmouse
->
state
=
PSMOUSE_CMD_MODE
;
psmouse
->
serio
=
serio
;
psmouse
->
dev
.
private
=
psmouse
;
psmouse_set_state
(
psmouse
,
PSMOUSE_INITIALIZING
);
serio
->
private
=
psmouse
;
if
(
serio_open
(
serio
,
d
e
v
))
{
if
(
serio_open
(
serio
,
d
r
v
))
{
kfree
(
psmouse
);
serio
->
private
=
NULL
;
return
;
goto
out
;
}
if
(
psmouse_probe
(
psmouse
)
<
0
)
{
serio_close
(
serio
);
kfree
(
psmouse
);
serio
->
private
=
NULL
;
return
;
goto
out
;
}
psmouse
->
type
=
psmouse_extensions
(
psmouse
,
psmouse_max_proto
,
1
);
...
...
@@ -711,63 +802,88 @@ static void psmouse_connect(struct serio *serio, struct serio_dev *dev)
printk
(
KERN_INFO
"input: %s on %s
\n
"
,
psmouse
->
devname
,
serio
->
phys
);
psmouse_set_state
(
psmouse
,
PSMOUSE_CMD_MODE
);
psmouse_initialize
(
psmouse
);
if
(
psmouse
->
ptport
)
{
printk
(
KERN_INFO
"serio: %s port at %s
\n
"
,
psmouse
->
ptport
->
serio
.
name
,
psmouse
->
phys
);
__serio_register_port
(
&
psmouse
->
ptport
->
serio
);
/* we have serio_sem */
if
(
psmouse
->
ptport
->
activate
)
psmouse
->
ptport
->
activate
(
psmouse
);
if
(
parent
&&
parent
->
pt_activate
)
parent
->
pt_activate
(
parent
);
if
(
serio
->
child
)
{
/*
* Nothing to be done here, serio core will detect that
* the driver set serio->child and will register it for us.
*/
printk
(
KERN_INFO
"serio: %s port at %s
\n
"
,
serio
->
child
->
name
,
psmouse
->
phys
);
}
psmouse_activate
(
psmouse
);
out:
/* If this is a pass-through port the parent awaits to be activated */
if
(
parent
)
psmouse_activate
(
parent
);
}
static
int
psmouse_reconnect
(
struct
serio
*
serio
)
{
struct
psmouse
*
psmouse
=
serio
->
private
;
struct
serio_dev
*
dev
=
serio
->
dev
;
struct
psmouse
*
parent
=
NULL
;
struct
serio_driver
*
drv
=
serio
->
drv
;
int
rc
=
-
1
;
if
(
!
d
e
v
||
!
psmouse
)
{
if
(
!
d
r
v
||
!
psmouse
)
{
printk
(
KERN_DEBUG
"psmouse: reconnect request, but serio is disconnected, ignoring...
\n
"
);
return
-
1
;
}
psmouse
->
state
=
PSMOUSE_CMD_MODE
;
psmouse
->
acking
=
psmouse
->
cmdcnt
=
psmouse
->
pktcnt
=
psmouse
->
out_of_sync
=
0
;
if
(
serio
->
parent
&&
(
serio
->
type
&
SERIO_TYPE
)
==
SERIO_PS_PSTHRU
)
{
parent
=
serio
->
parent
->
private
;
psmouse_deactivate
(
parent
);
}
psmouse_set_state
(
psmouse
,
PSMOUSE_INITIALIZING
);
if
(
psmouse
->
reconnect
)
{
if
(
psmouse
->
reconnect
(
psmouse
))
return
-
1
;
goto
out
;
}
else
if
(
psmouse_probe
(
psmouse
)
<
0
||
psmouse
->
type
!=
psmouse_extensions
(
psmouse
,
psmouse_max_proto
,
0
))
return
-
1
;
goto
out
;
/* ok, the device type (and capabilities) match the old one,
* we can continue using it, complete intialization
*/
psmouse_set_state
(
psmouse
,
PSMOUSE_CMD_MODE
);
psmouse_initialize
(
psmouse
);
if
(
psmouse
->
ptport
)
{
if
(
psmouse_reconnect
(
&
psmouse
->
ptport
->
serio
))
{
__serio_unregister_port
(
&
psmouse
->
ptport
->
serio
);
__serio_register_port
(
&
psmouse
->
ptport
->
serio
);
if
(
psmouse
->
ptport
->
activate
)
psmouse
->
ptport
->
activate
(
psmouse
);
}
}
if
(
parent
&&
parent
->
pt_activate
)
parent
->
pt_activate
(
parent
);
psmouse_activate
(
psmouse
);
return
0
;
rc
=
0
;
out:
/* If this is a pass-through port the parent waits to be activated */
if
(
parent
)
psmouse_activate
(
parent
);
return
rc
;
}
static
struct
serio_dev
psmouse_dev
=
{
.
interrupt
=
psmouse_interrupt
,
.
connect
=
psmouse_connect
,
.
reconnect
=
psmouse_reconnect
,
.
disconnect
=
psmouse_disconnect
,
.
cleanup
=
psmouse_cleanup
,
static
struct
serio_driver
psmouse_drv
=
{
.
driver
=
{
.
name
=
"psmouse"
,
},
.
description
=
DRIVER_DESC
,
.
interrupt
=
psmouse_interrupt
,
.
connect
=
psmouse_connect
,
.
reconnect
=
psmouse_reconnect
,
.
disconnect
=
psmouse_disconnect
,
.
cleanup
=
psmouse_cleanup
,
};
static
inline
void
psmouse_parse_proto
(
void
)
...
...
@@ -787,13 +903,13 @@ static inline void psmouse_parse_proto(void)
int
__init
psmouse_init
(
void
)
{
psmouse_parse_proto
();
serio_register_d
evice
(
&
psmouse_de
v
);
serio_register_d
river
(
&
psmouse_dr
v
);
return
0
;
}
void
__exit
psmouse_exit
(
void
)
{
serio_unregister_d
evice
(
&
psmouse_de
v
);
serio_unregister_d
river
(
&
psmouse_dr
v
);
}
module_init
(
psmouse_init
);
...
...
drivers/input/mouse/psmouse.h
View file @
73df7566
...
...
@@ -9,6 +9,7 @@
#define PSMOUSE_CMD_GETID 0x02f2
#define PSMOUSE_CMD_SETRATE 0x10f3
#define PSMOUSE_CMD_ENABLE 0x00f4
#define PSMOUSE_CMD_DISABLE 0x00f5
#define PSMOUSE_CMD_RESET_DIS 0x00f6
#define PSMOUSE_CMD_RESET_BAT 0x02ff
...
...
@@ -17,10 +18,17 @@
#define PSMOUSE_RET_ACK 0xfa
#define PSMOUSE_RET_NAK 0xfe
/* psmouse states */
#define PSMOUSE_CMD_MODE 0
#define PSMOUSE_ACTIVATED 1
#define PSMOUSE_IGNORE 2
#define PSMOUSE_FLAG_ACK 0
/* Waiting for ACK/NAK */
#define PSMOUSE_FLAG_CMD 1
/* Waiting for command to finish */
#define PSMOUSE_FLAG_CMD1 2
/* Waiting for the first byte of command response */
#define PSMOUSE_FLAG_WAITID 3
/* Command execiting is GET ID */
enum
psmouse_state
{
PSMOUSE_IGNORE
,
PSMOUSE_INITIALIZING
,
PSMOUSE_CMD_MODE
,
PSMOUSE_ACTIVATED
,
};
/* psmouse protocol handler return codes */
typedef
enum
{
...
...
@@ -29,20 +37,10 @@ typedef enum {
PSMOUSE_FULL_PACKET
}
psmouse_ret_t
;
struct
psmouse
;
struct
psmouse_ptport
{
struct
serio
serio
;
void
(
*
activate
)(
struct
psmouse
*
parent
);
void
(
*
deactivate
)(
struct
psmouse
*
parent
);
};
struct
psmouse
{
void
*
private
;
struct
input_dev
dev
;
struct
serio
*
serio
;
struct
psmouse_ptport
*
ptport
;
char
*
vendor
;
char
*
name
;
unsigned
char
cmdbuf
[
8
];
...
...
@@ -53,16 +51,22 @@ struct psmouse {
unsigned
char
model
;
unsigned
long
last
;
unsigned
long
out_of_sync
;
unsigned
char
state
;
char
acking
;
volatile
char
ack
;
enum
psmouse_state
state
;
unsigned
char
nak
;
char
error
;
char
devname
[
64
];
char
phys
[
32
];
unsigned
long
flags
;
psmouse_ret_t
(
*
protocol_handler
)(
struct
psmouse
*
psmouse
,
struct
pt_regs
*
regs
);
/* Used to signal completion from interrupt handler */
wait_queue_head_t
wait
;
psmouse_ret_t
(
*
protocol_handler
)(
struct
psmouse
*
psmouse
,
struct
pt_regs
*
regs
);
int
(
*
reconnect
)(
struct
psmouse
*
psmouse
);
void
(
*
disconnect
)(
struct
psmouse
*
psmouse
);
void
(
*
pt_activate
)(
struct
psmouse
*
psmouse
);
void
(
*
pt_deactivate
)(
struct
psmouse
*
psmouse
);
};
#define PSMOUSE_PS2 1
...
...
drivers/input/mouse/sermouse.c
View file @
73df7566
...
...
@@ -37,8 +37,10 @@
#include <linux/serio.h>
#include <linux/init.h>
#define DRIVER_DESC "Serial mouse driver"
MODULE_AUTHOR
(
"Vojtech Pavlik <vojtech@ucw.cz>"
);
MODULE_DESCRIPTION
(
"Serial mouse driver"
);
MODULE_DESCRIPTION
(
DRIVER_DESC
);
MODULE_LICENSE
(
"GPL"
);
static
char
*
sermouse_protocols
[]
=
{
"None"
,
"Mouse Systems Mouse"
,
"Sun Mouse"
,
"Microsoft Mouse"
,
...
...
@@ -237,7 +239,7 @@ static void sermouse_disconnect(struct serio *serio)
* an unhandled serio port is found.
*/
static
void
sermouse_connect
(
struct
serio
*
serio
,
struct
serio_d
ev
*
de
v
)
static
void
sermouse_connect
(
struct
serio
*
serio
,
struct
serio_d
river
*
dr
v
)
{
struct
sermouse
*
sermouse
;
unsigned
char
c
;
...
...
@@ -279,7 +281,7 @@ static void sermouse_connect(struct serio *serio, struct serio_dev *dev)
sermouse
->
dev
.
id
.
product
=
c
;
sermouse
->
dev
.
id
.
version
=
0x0100
;
if
(
serio_open
(
serio
,
d
e
v
))
{
if
(
serio_open
(
serio
,
d
r
v
))
{
kfree
(
sermouse
);
return
;
}
...
...
@@ -289,21 +291,25 @@ static void sermouse_connect(struct serio *serio, struct serio_dev *dev)
printk
(
KERN_INFO
"input: %s on %s
\n
"
,
sermouse_protocols
[
sermouse
->
type
],
serio
->
phys
);
}
static
struct
serio_dev
sermouse_dev
=
{
.
interrupt
=
sermouse_interrupt
,
.
connect
=
sermouse_connect
,
.
disconnect
=
sermouse_disconnect
static
struct
serio_driver
sermouse_drv
=
{
.
driver
=
{
.
name
=
"sermouse"
,
},
.
description
=
DRIVER_DESC
,
.
interrupt
=
sermouse_interrupt
,
.
connect
=
sermouse_connect
,
.
disconnect
=
sermouse_disconnect
,
};
int
__init
sermouse_init
(
void
)
{
serio_register_d
evice
(
&
sermouse_de
v
);
serio_register_d
river
(
&
sermouse_dr
v
);
return
0
;
}
void
__exit
sermouse_exit
(
void
)
{
serio_unregister_d
evice
(
&
sermouse_de
v
);
serio_unregister_d
river
(
&
sermouse_dr
v
);
}
module_init
(
sermouse_init
);
...
...
drivers/input/mouse/synaptics.c
View file @
73df7566
...
...
@@ -212,9 +212,9 @@ static int synaptics_set_mode(struct psmouse *psmouse, int mode)
/*****************************************************************************
* Synaptics pass-through PS/2 port support
****************************************************************************/
static
int
synaptics_pt_write
(
struct
serio
*
port
,
unsigned
char
c
)
static
int
synaptics_pt_write
(
struct
serio
*
serio
,
unsigned
char
c
)
{
struct
psmouse
*
parent
=
port
->
driver
;
struct
psmouse
*
parent
=
serio
->
parent
->
private
;
char
rate_param
=
SYN_PS_CLIENT_CMD
;
/* indicates that we want pass-through port */
if
(
psmouse_sliced_command
(
parent
,
c
))
...
...
@@ -233,22 +233,19 @@ static void synaptics_pass_pt_packet(struct serio *ptport, unsigned char *packet
{
struct
psmouse
*
child
=
ptport
->
private
;
if
(
child
)
{
if
(
child
->
state
==
PSMOUSE_ACTIVATED
)
{
serio_interrupt
(
ptport
,
packet
[
1
],
0
,
NULL
);
serio_interrupt
(
ptport
,
packet
[
4
],
0
,
NULL
);
serio_interrupt
(
ptport
,
packet
[
5
],
0
,
NULL
);
if
(
child
->
type
>=
PSMOUSE_GENPS
)
serio_interrupt
(
ptport
,
packet
[
2
],
0
,
NULL
);
}
else
if
(
child
->
state
!=
PSMOUSE_IGNORE
)
{
serio_interrupt
(
ptport
,
packet
[
1
],
0
,
NULL
);
}
}
if
(
child
&&
child
->
state
==
PSMOUSE_ACTIVATED
)
{
serio_interrupt
(
ptport
,
packet
[
1
],
0
,
NULL
);
serio_interrupt
(
ptport
,
packet
[
4
],
0
,
NULL
);
serio_interrupt
(
ptport
,
packet
[
5
],
0
,
NULL
);
if
(
child
->
type
>=
PSMOUSE_GENPS
)
serio_interrupt
(
ptport
,
packet
[
2
],
0
,
NULL
);
}
else
serio_interrupt
(
ptport
,
packet
[
1
],
0
,
NULL
);
}
static
void
synaptics_pt_activate
(
struct
psmouse
*
psmouse
)
{
struct
psmouse
*
child
=
psmouse
->
ptport
->
serio
.
private
;
struct
psmouse
*
child
=
psmouse
->
serio
->
child
->
private
;
/* adjust the touchpad to child's choice of protocol */
if
(
child
&&
child
->
type
>=
PSMOUSE_GENPS
)
{
...
...
@@ -259,23 +256,25 @@ static void synaptics_pt_activate(struct psmouse *psmouse)
static
void
synaptics_pt_create
(
struct
psmouse
*
psmouse
)
{
struct
psmouse_ptport
*
port
;
struct
serio
*
serio
;
psmouse
->
ptport
=
port
=
kmalloc
(
sizeof
(
struct
psmouse_ptport
),
GFP_KERNEL
);
if
(
!
port
)
{
serio
=
kmalloc
(
sizeof
(
struct
serio
),
GFP_KERNEL
);
if
(
!
serio
)
{
printk
(
KERN_ERR
"synaptics: not enough memory to allocate pass-through port
\n
"
);
return
;
}
memset
(
port
,
0
,
sizeof
(
struct
psmouse_ptport
));
memset
(
serio
,
0
,
sizeof
(
struct
serio
));
serio
->
type
=
SERIO_PS_PSTHRU
;
strlcpy
(
serio
->
name
,
"Synaptics pass-through"
,
sizeof
(
serio
->
name
));
strlcpy
(
serio
->
phys
,
"synaptics-pt/serio0"
,
sizeof
(
serio
->
name
));
serio
->
write
=
synaptics_pt_write
;
serio
->
parent
=
psmouse
->
serio
;
port
->
serio
.
type
=
SERIO_PS_PSTHRU
;
port
->
serio
.
name
=
"Synaptics pass-through"
;
port
->
serio
.
phys
=
"synaptics-pt/serio0"
;
port
->
serio
.
write
=
synaptics_pt_write
;
port
->
serio
.
driver
=
psmouse
;
psmouse
->
pt_activate
=
synaptics_pt_activate
;
p
ort
->
activate
=
synaptics_pt_activate
;
p
smouse
->
serio
->
child
=
serio
;
}
/*****************************************************************************
...
...
@@ -470,9 +469,10 @@ static psmouse_ret_t synaptics_process_byte(struct psmouse *psmouse, struct pt_r
if
(
unlikely
(
priv
->
pkt_type
==
SYN_NEWABS
))
priv
->
pkt_type
=
synaptics_detect_pkt_type
(
psmouse
);
if
(
psmouse
->
ptport
&&
psmouse
->
ptport
->
serio
.
dev
&&
synaptics_is_pt_packet
(
psmouse
->
packet
))
synaptics_pass_pt_packet
(
&
psmouse
->
ptport
->
serio
,
psmouse
->
packet
);
else
if
(
SYN_CAP_PASS_THROUGH
(
priv
->
capabilities
)
&&
synaptics_is_pt_packet
(
psmouse
->
packet
))
{
if
(
psmouse
->
serio
->
child
)
synaptics_pass_pt_packet
(
psmouse
->
serio
->
child
,
psmouse
->
packet
);
}
else
synaptics_process_packet
(
psmouse
);
return
PSMOUSE_FULL_PACKET
;
...
...
drivers/input/mouse/vsxxxaa.c
View file @
73df7566
...
...
@@ -82,8 +82,10 @@
#include <linux/serio.h>
#include <linux/init.h>
#define DRIVER_DESC "Serial DEC VSXXX-AA/GA mouse / DEC tablet driver"
MODULE_AUTHOR
(
"Jan-Benedict Glaw <jbglaw@lug-owl.de>"
);
MODULE_DESCRIPTION
(
"Serial DEC VSXXX-AA/GA mouse / DEC tablet driver"
);
MODULE_DESCRIPTION
(
DRIVER_DESC
);
MODULE_LICENSE
(
"GPL"
);
#undef VSXXXAA_DEBUG
...
...
@@ -482,7 +484,7 @@ vsxxxaa_disconnect (struct serio *serio)
}
static
void
vsxxxaa_connect
(
struct
serio
*
serio
,
struct
serio_d
ev
*
de
v
)
vsxxxaa_connect
(
struct
serio
*
serio
,
struct
serio_d
river
*
dr
v
)
{
struct
vsxxxaa
*
mouse
;
...
...
@@ -524,7 +526,7 @@ vsxxxaa_connect (struct serio *serio, struct serio_dev *dev)
mouse
->
dev
.
id
.
bustype
=
BUS_RS232
;
mouse
->
serio
=
serio
;
if
(
serio_open
(
serio
,
d
e
v
))
{
if
(
serio_open
(
serio
,
d
r
v
))
{
kfree
(
mouse
);
return
;
}
...
...
@@ -540,23 +542,27 @@ vsxxxaa_connect (struct serio *serio, struct serio_dev *dev)
printk
(
KERN_INFO
"input: %s on %s
\n
"
,
mouse
->
name
,
mouse
->
phys
);
}
static
struct
serio_dev
vsxxxaa_dev
=
{
.
connect
=
vsxxxaa_connect
,
.
interrupt
=
vsxxxaa_interrupt
,
.
disconnect
=
vsxxxaa_disconnect
,
static
struct
serio_driver
vsxxxaa_drv
=
{
.
driver
=
{
.
name
=
"vsxxxaa"
,
},
.
description
=
DRIVER_DESC
,
.
connect
=
vsxxxaa_connect
,
.
interrupt
=
vsxxxaa_interrupt
,
.
disconnect
=
vsxxxaa_disconnect
,
};
int
__init
vsxxxaa_init
(
void
)
{
serio_register_d
evice
(
&
vsxxxaa_de
v
);
serio_register_d
river
(
&
vsxxxaa_dr
v
);
return
0
;
}
void
__exit
vsxxxaa_exit
(
void
)
{
serio_unregister_d
evice
(
&
vsxxxaa_de
v
);
serio_unregister_d
river
(
&
vsxxxaa_dr
v
);
}
module_init
(
vsxxxaa_init
);
...
...
drivers/input/mousedev.c
View file @
73df7566
...
...
@@ -48,8 +48,15 @@ static int yres = CONFIG_INPUT_MOUSEDEV_SCREEN_Y;
module_param
(
yres
,
uint
,
0
);
MODULE_PARM_DESC
(
yres
,
"Vertical screen resolution"
);
struct
mousedev_motion
{
static
unsigned
tap_time
=
200
;
module_param
(
tap_time
,
uint
,
0
);
MODULE_PARM_DESC
(
tap_time
,
"Tap time for touchpads in absolute mode (msecs)"
);
struct
mousedev_hw_data
{
int
dx
,
dy
,
dz
;
int
x
,
y
;
int
abs_event
;
unsigned
long
buttons
;
};
struct
mousedev
{
...
...
@@ -61,22 +68,38 @@ struct mousedev {
struct
list_head
list
;
struct
input_handle
handle
;
struct
mousedev_motion
packet
;
unsigned
long
buttons
;
struct
mousedev_hw_data
packet
;
unsigned
int
pkt_count
;
int
old_x
[
4
],
old_y
[
4
];
unsigned
int
touch
;
unsigned
long
touch
;
};
enum
mousedev_emul
{
MOUSEDEV_EMUL_PS2
,
MOUSEDEV_EMUL_IMPS
,
MOUSEDEV_EMUL_EXPS
};
struct
mousedev_motion
{
int
dx
,
dy
,
dz
;
unsigned
long
buttons
;
};
#define PACKET_QUEUE_LEN 16
struct
mousedev_list
{
struct
fasync_struct
*
fasync
;
struct
mousedev
*
mousedev
;
struct
list_head
node
;
int
dx
,
dy
,
dz
;
unsigned
long
buttons
;
struct
mousedev_motion
packets
[
PACKET_QUEUE_LEN
];
unsigned
int
head
,
tail
;
spinlock_t
packet_lock
;
int
pos_x
,
pos_y
;
signed
char
ps2
[
6
];
unsigned
char
ready
,
buffer
,
bufsiz
;
unsigned
char
mode
,
imexseq
,
impsseq
;
unsigned
char
imexseq
,
impsseq
;
enum
mousedev_emul
mode
;
};
#define MOUSEDEV_SEQ_LEN 6
...
...
@@ -119,15 +142,19 @@ static void mousedev_abs_event(struct input_dev *dev, struct mousedev *mousedev,
case
ABS_X
:
size
=
dev
->
absmax
[
ABS_X
]
-
dev
->
absmin
[
ABS_X
];
if
(
size
==
0
)
size
=
xres
;
mousedev
->
packet
.
dx
=
(
value
*
xres
-
mousedev
->
old_x
[
0
])
/
size
;
mousedev
->
old_x
[
0
]
=
mousedev
->
packet
.
dx
*
size
;
if
(
value
>
dev
->
absmax
[
ABS_X
])
value
=
dev
->
absmax
[
ABS_X
];
if
(
value
<
dev
->
absmin
[
ABS_X
])
value
=
dev
->
absmin
[
ABS_X
];
mousedev
->
packet
.
x
=
((
value
-
dev
->
absmin
[
ABS_X
])
*
xres
)
/
size
;
mousedev
->
packet
.
abs_event
=
1
;
break
;
case
ABS_Y
:
size
=
dev
->
absmax
[
ABS_Y
]
-
dev
->
absmin
[
ABS_Y
];
if
(
size
==
0
)
size
=
yres
;
mousedev
->
packet
.
dy
=
(
value
*
yres
-
mousedev
->
old_y
[
0
])
/
size
;
mousedev
->
old_y
[
0
]
=
mousedev
->
packet
.
dy
*
size
;
if
(
value
>
dev
->
absmax
[
ABS_Y
])
value
=
dev
->
absmax
[
ABS_Y
];
if
(
value
<
dev
->
absmin
[
ABS_Y
])
value
=
dev
->
absmin
[
ABS_Y
];
mousedev
->
packet
.
y
=
yres
-
((
value
-
dev
->
absmin
[
ABS_Y
])
*
yres
)
/
size
;
mousedev
->
packet
.
abs_event
=
1
;
break
;
}
}
...
...
@@ -165,30 +192,82 @@ static void mousedev_key_event(struct mousedev *mousedev, unsigned int code, int
}
if
(
value
)
{
set_bit
(
index
,
&
mousedev
->
buttons
);
set_bit
(
index
,
&
mousedev_mix
.
buttons
);
set_bit
(
index
,
&
mousedev
->
packet
.
buttons
);
set_bit
(
index
,
&
mousedev_mix
.
packet
.
buttons
);
}
else
{
clear_bit
(
index
,
&
mousedev
->
buttons
);
clear_bit
(
index
,
&
mousedev_mix
.
buttons
);
clear_bit
(
index
,
&
mousedev
->
packet
.
buttons
);
clear_bit
(
index
,
&
mousedev_mix
.
packet
.
buttons
);
}
}
static
void
mousedev_notify_readers
(
struct
mousedev
*
mousedev
,
struct
mousedev_
motion
*
packet
)
static
void
mousedev_notify_readers
(
struct
mousedev
*
mousedev
,
struct
mousedev_
hw_data
*
packet
)
{
struct
mousedev_list
*
list
;
struct
mousedev_motion
*
p
;
unsigned
long
flags
;
list_for_each_entry
(
list
,
&
mousedev
->
list
,
node
)
{
list
->
dx
+=
packet
->
dx
;
list
->
dy
+=
packet
->
dy
;
list
->
dz
+=
packet
->
dz
;
list
->
buttons
=
mousedev
->
buttons
;
spin_lock_irqsave
(
&
list
->
packet_lock
,
flags
);
p
=
&
list
->
packets
[
list
->
head
];
if
(
list
->
ready
&&
p
->
buttons
!=
packet
->
buttons
)
{
unsigned
int
new_head
=
(
list
->
head
+
1
)
%
PACKET_QUEUE_LEN
;
if
(
new_head
!=
list
->
tail
)
{
p
=
&
list
->
packets
[
list
->
head
=
new_head
];
memset
(
p
,
0
,
sizeof
(
struct
mousedev_motion
));
}
}
if
(
packet
->
abs_event
)
{
p
->
dx
+=
packet
->
x
-
list
->
pos_x
;
p
->
dy
+=
packet
->
y
-
list
->
pos_y
;
list
->
pos_x
=
packet
->
x
;
list
->
pos_y
=
packet
->
y
;
}
list
->
pos_x
+=
packet
->
dx
;
list
->
pos_x
=
list
->
pos_x
<
0
?
0
:
(
list
->
pos_x
>=
xres
?
xres
:
list
->
pos_x
);
list
->
pos_y
+=
packet
->
dy
;
list
->
pos_y
=
list
->
pos_y
<
0
?
0
:
(
list
->
pos_y
>=
yres
?
yres
:
list
->
pos_y
);
p
->
dx
+=
packet
->
dx
;
p
->
dy
+=
packet
->
dy
;
p
->
dz
+=
packet
->
dz
;
p
->
buttons
=
mousedev
->
packet
.
buttons
;
list
->
ready
=
1
;
spin_unlock_irqrestore
(
&
list
->
packet_lock
,
flags
);
kill_fasync
(
&
list
->
fasync
,
SIGIO
,
POLL_IN
);
}
wake_up_interruptible
(
&
mousedev
->
wait
);
}
static
void
mousedev_touchpad_touch
(
struct
mousedev
*
mousedev
,
int
value
)
{
if
(
!
value
)
{
if
(
mousedev
->
touch
&&
time_before
(
jiffies
,
mousedev
->
touch
+
msecs_to_jiffies
(
tap_time
)))
{
/*
* Toggle left button to emulate tap.
* We rely on the fact that mousedev_mix always has 0
* motion packet so we won't mess current position.
*/
set_bit
(
0
,
&
mousedev
->
packet
.
buttons
);
set_bit
(
0
,
&
mousedev_mix
.
packet
.
buttons
);
mousedev_notify_readers
(
mousedev
,
&
mousedev_mix
.
packet
);
mousedev_notify_readers
(
&
mousedev_mix
,
&
mousedev_mix
.
packet
);
clear_bit
(
0
,
&
mousedev
->
packet
.
buttons
);
clear_bit
(
0
,
&
mousedev_mix
.
packet
.
buttons
);
}
mousedev
->
touch
=
mousedev
->
pkt_count
=
0
;
}
else
if
(
!
mousedev
->
touch
)
mousedev
->
touch
=
jiffies
;
}
static
void
mousedev_event
(
struct
input_handle
*
handle
,
unsigned
int
type
,
unsigned
int
code
,
int
value
)
{
struct
mousedev
*
mousedev
=
handle
->
private
;
...
...
@@ -212,12 +291,8 @@ static void mousedev_event(struct input_handle *handle, unsigned int type, unsig
case
EV_KEY
:
if
(
value
!=
2
)
{
if
(
code
==
BTN_TOUCH
&&
test_bit
(
BTN_TOOL_FINGER
,
handle
->
dev
->
keybit
))
{
/* Handle touchpad data */
mousedev
->
touch
=
value
;
if
(
!
mousedev
->
touch
)
mousedev
->
pkt_count
=
0
;
}
if
(
code
==
BTN_TOUCH
&&
test_bit
(
BTN_TOOL_FINGER
,
handle
->
dev
->
keybit
))
mousedev_touchpad_touch
(
mousedev
,
value
);
else
mousedev_key_event
(
mousedev
,
code
,
value
);
}
...
...
@@ -237,7 +312,8 @@ static void mousedev_event(struct input_handle *handle, unsigned int type, unsig
mousedev_notify_readers
(
mousedev
,
&
mousedev
->
packet
);
mousedev_notify_readers
(
&
mousedev_mix
,
&
mousedev
->
packet
);
memset
(
&
mousedev
->
packet
,
0
,
sizeof
(
struct
mousedev_motion
));
mousedev
->
packet
.
dx
=
mousedev
->
packet
.
dy
=
mousedev
->
packet
.
dz
=
0
;
mousedev
->
packet
.
abs_event
=
0
;
}
break
;
}
...
...
@@ -322,6 +398,9 @@ static int mousedev_open(struct inode * inode, struct file * file)
return
-
ENOMEM
;
memset
(
list
,
0
,
sizeof
(
struct
mousedev_list
));
spin_lock_init
(
&
list
->
packet_lock
);
list
->
pos_x
=
xres
/
2
;
list
->
pos_y
=
yres
/
2
;
list
->
mousedev
=
mousedev_table
[
i
];
list_add_tail
(
&
list
->
node
,
&
mousedev_table
[
i
]
->
list
);
file
->
private_data
=
list
;
...
...
@@ -341,32 +420,56 @@ static int mousedev_open(struct inode * inode, struct file * file)
return
0
;
}
static
void
mousedev_packet
(
struct
mousedev_list
*
list
,
unsigned
char
off
)
static
inline
int
mousedev_limit_delta
(
int
delta
,
int
limit
)
{
list
->
ps2
[
off
]
=
0x08
|
((
list
->
dx
<
0
)
<<
4
)
|
((
list
->
dy
<
0
)
<<
5
)
|
(
list
->
buttons
&
0x07
);
list
->
ps2
[
off
+
1
]
=
(
list
->
dx
>
127
?
127
:
(
list
->
dx
<
-
127
?
-
127
:
list
->
dx
));
list
->
ps2
[
off
+
2
]
=
(
list
->
dy
>
127
?
127
:
(
list
->
dy
<
-
127
?
-
127
:
list
->
dy
));
list
->
dx
-=
list
->
ps2
[
off
+
1
];
list
->
dy
-=
list
->
ps2
[
off
+
2
];
list
->
bufsiz
=
off
+
3
;
if
(
list
->
mode
==
2
)
{
list
->
ps2
[
off
+
3
]
=
(
list
->
dz
>
7
?
7
:
(
list
->
dz
<
-
7
?
-
7
:
list
->
dz
));
list
->
dz
-=
list
->
ps2
[
off
+
3
];
list
->
ps2
[
off
+
3
]
=
(
list
->
ps2
[
off
+
3
]
&
0x0f
)
|
((
list
->
buttons
&
0x18
)
<<
1
);
list
->
bufsiz
++
;
}
else
{
list
->
ps2
[
off
]
|=
((
list
->
buttons
&
0x10
)
>>
3
)
|
((
list
->
buttons
&
0x08
)
>>
1
);
return
delta
>
limit
?
limit
:
(
delta
<
-
limit
?
-
limit
:
delta
);
}
static
void
mousedev_packet
(
struct
mousedev_list
*
list
,
signed
char
*
ps2_data
)
{
struct
mousedev_motion
*
p
;
unsigned
long
flags
;
spin_lock_irqsave
(
&
list
->
packet_lock
,
flags
);
p
=
&
list
->
packets
[
list
->
tail
];
ps2_data
[
0
]
=
0x08
|
((
p
->
dx
<
0
)
<<
4
)
|
((
p
->
dy
<
0
)
<<
5
)
|
(
p
->
buttons
&
0x07
);
ps2_data
[
1
]
=
mousedev_limit_delta
(
p
->
dx
,
127
);
ps2_data
[
2
]
=
mousedev_limit_delta
(
p
->
dy
,
127
);
p
->
dx
-=
ps2_data
[
1
];
p
->
dy
-=
ps2_data
[
2
];
switch
(
list
->
mode
)
{
case
MOUSEDEV_EMUL_EXPS
:
ps2_data
[
3
]
=
mousedev_limit_delta
(
p
->
dz
,
127
);
p
->
dz
-=
ps2_data
[
3
];
ps2_data
[
3
]
=
(
ps2_data
[
3
]
&
0x0f
)
|
((
p
->
buttons
&
0x18
)
<<
1
);
list
->
bufsiz
=
4
;
break
;
case
MOUSEDEV_EMUL_IMPS
:
ps2_data
[
0
]
|=
((
p
->
buttons
&
0x10
)
>>
3
)
|
((
p
->
buttons
&
0x08
)
>>
1
);
ps2_data
[
3
]
=
mousedev_limit_delta
(
p
->
dz
,
127
);
p
->
dz
-=
ps2_data
[
3
];
list
->
bufsiz
=
4
;
break
;
case
MOUSEDEV_EMUL_PS2
:
default:
ps2_data
[
0
]
|=
((
p
->
buttons
&
0x10
)
>>
3
)
|
((
p
->
buttons
&
0x08
)
>>
1
);
p
->
dz
=
0
;
list
->
bufsiz
=
3
;
break
;
}
if
(
list
->
mode
==
1
)
{
list
->
ps2
[
off
+
3
]
=
(
list
->
dz
>
127
?
127
:
(
list
->
dz
<
-
127
?
-
127
:
list
->
dz
));
list
->
dz
-=
list
->
ps2
[
off
+
3
];
list
->
bufsiz
++
;
if
(
!
p
->
dx
&&
!
p
->
dy
&&
!
p
->
dz
)
{
if
(
list
->
tail
!=
list
->
head
)
list
->
tail
=
(
list
->
tail
+
1
)
%
PACKET_QUEUE_LEN
;
if
(
list
->
tail
==
list
->
head
)
list
->
ready
=
0
;
}
if
(
!
list
->
dx
&&
!
list
->
dy
&&
(
!
list
->
mode
||
!
list
->
dz
))
list
->
ready
=
0
;
list
->
buffer
=
list
->
bufsiz
;
spin_unlock_irqrestore
(
&
list
->
packet_lock
,
flags
);
}
...
...
@@ -384,31 +487,31 @@ static ssize_t mousedev_write(struct file * file, const char __user * buffer, si
if
(
c
==
mousedev_imex_seq
[
list
->
imexseq
])
{
if
(
++
list
->
imexseq
==
MOUSEDEV_SEQ_LEN
)
{
list
->
imexseq
=
0
;
list
->
mode
=
2
;
list
->
mode
=
MOUSEDEV_EMUL_EXPS
;
}
}
else
list
->
imexseq
=
0
;
if
(
c
==
mousedev_imps_seq
[
list
->
impsseq
])
{
if
(
++
list
->
impsseq
==
MOUSEDEV_SEQ_LEN
)
{
list
->
impsseq
=
0
;
list
->
mode
=
1
;
list
->
mode
=
MOUSEDEV_EMUL_IMPS
;
}
}
else
list
->
impsseq
=
0
;
list
->
ps2
[
0
]
=
0xfa
;
list
->
bufsiz
=
1
;
switch
(
c
)
{
case
0xeb
:
/* Poll */
mousedev_packet
(
list
,
1
);
mousedev_packet
(
list
,
&
list
->
ps2
[
1
]);
list
->
bufsiz
++
;
/* account for leading ACK */
break
;
case
0xf2
:
/* Get ID */
switch
(
list
->
mode
)
{
case
0
:
list
->
ps2
[
1
]
=
0
;
break
;
case
1
:
list
->
ps2
[
1
]
=
3
;
break
;
case
2
:
list
->
ps2
[
1
]
=
4
;
break
;
case
MOUSEDEV_EMUL_PS2
:
list
->
ps2
[
1
]
=
0
;
break
;
case
MOUSEDEV_EMUL_IMPS
:
list
->
ps2
[
1
]
=
3
;
break
;
case
MOUSEDEV_EMUL_EXPS
:
list
->
ps2
[
1
]
=
4
;
break
;
}
list
->
bufsiz
=
2
;
break
;
...
...
@@ -419,13 +522,15 @@ static ssize_t mousedev_write(struct file * file, const char __user * buffer, si
break
;
case
0xff
:
/* Reset */
list
->
impsseq
=
0
;
list
->
imexseq
=
0
;
list
->
mode
=
0
;
list
->
ps2
[
1
]
=
0xaa
;
list
->
ps2
[
2
]
=
0x00
;
list
->
impsseq
=
list
->
imexseq
=
0
;
list
->
mode
=
MOUSEDEV_EMUL_PS2
;
list
->
ps2
[
1
]
=
0xaa
;
list
->
ps2
[
2
]
=
0x00
;
list
->
bufsiz
=
3
;
break
;
default:
list
->
bufsiz
=
1
;
break
;
}
list
->
buffer
=
list
->
bufsiz
;
...
...
@@ -446,13 +551,19 @@ static ssize_t mousedev_read(struct file * file, char __user * buffer, size_t co
if
(
!
list
->
ready
&&
!
list
->
buffer
&&
(
file
->
f_flags
&
O_NONBLOCK
))
return
-
EAGAIN
;
retval
=
wait_event_interruptible
(
list
->
mousedev
->
wait
,
list
->
ready
||
list
->
buffer
);
retval
=
wait_event_interruptible
(
list
->
mousedev
->
wait
,
!
list
->
mousedev
->
exist
||
list
->
ready
||
list
->
buffer
);
if
(
retval
)
return
retval
;
if
(
!
list
->
buffer
&&
list
->
ready
)
mousedev_packet
(
list
,
0
);
if
(
!
list
->
mousedev
->
exist
)
return
-
ENODEV
;
if
(
!
list
->
buffer
&&
list
->
ready
)
{
mousedev_packet
(
list
,
list
->
ps2
);
list
->
buffer
=
list
->
bufsiz
;
}
if
(
count
>
list
->
buffer
)
count
=
list
->
buffer
;
...
...
drivers/input/serio/Kconfig
View file @
73df7566
...
...
@@ -130,3 +130,19 @@ config SERIO_MACEPS2
To compile this driver as a module, choose M here: the
module will be called maceps2.
config SERIO_RAW
tristate "Raw access to serio ports"
depends on SERIO
help
Say Y here if you want to have raw access to serio ports, such as
AUX ports on i8042 keyboard controller. Each serio port that is
bound to this driver will be accessible via a char device with
major 10 and dynamically allocated minor. The driver will try
allocating minor 1 (that historically corresponds to /dev/psaux)
first. To bind this driver to a serio port use sysfs interface:
echo -n "serio_raw" > /sys/bus/serio/devices/serioX/driver
To compile this driver as a module, choose M here: the
module will be called serio_raw.
drivers/input/serio/Makefile
View file @
73df7566
...
...
@@ -17,3 +17,4 @@ obj-$(CONFIG_SERIO_98KBD) += 98kbd-io.o
obj-$(CONFIG_SERIO_GSCPS2)
+=
gscps2.o
obj-$(CONFIG_SERIO_PCIPS2)
+=
pcips2.o
obj-$(CONFIG_SERIO_MACEPS2)
+=
maceps2.o
obj-$(CONFIG_SERIO_RAW)
+=
serio_raw.o
drivers/input/serio/ambakmi.c
View file @
73df7566
...
...
@@ -29,7 +29,7 @@
#define KMI_BASE (kmi->base)
struct
amba_kmi_port
{
struct
serio
io
;
struct
serio
*
io
;
struct
clk
*
clk
;
unsigned
char
*
base
;
unsigned
int
irq
;
...
...
@@ -44,7 +44,7 @@ static irqreturn_t amba_kmi_int(int irq, void *dev_id, struct pt_regs *regs)
int
handled
=
IRQ_NONE
;
while
(
status
&
KMIIR_RXINTR
)
{
serio_interrupt
(
&
kmi
->
io
,
readb
(
KMIDATA
),
0
,
regs
);
serio_interrupt
(
kmi
->
io
,
readb
(
KMIDATA
),
0
,
regs
);
status
=
readb
(
KMIIR
);
handled
=
IRQ_HANDLED
;
}
...
...
@@ -54,7 +54,7 @@ static irqreturn_t amba_kmi_int(int irq, void *dev_id, struct pt_regs *regs)
static
int
amba_kmi_write
(
struct
serio
*
io
,
unsigned
char
val
)
{
struct
amba_kmi_port
*
kmi
=
io
->
driver
;
struct
amba_kmi_port
*
kmi
=
io
->
port_data
;
unsigned
int
timeleft
=
10000
;
/* timeout in 100ms */
while
((
readb
(
KMISTAT
)
&
KMISTAT_TXEMPTY
)
==
0
&&
timeleft
--
)
...
...
@@ -68,7 +68,7 @@ static int amba_kmi_write(struct serio *io, unsigned char val)
static
int
amba_kmi_open
(
struct
serio
*
io
)
{
struct
amba_kmi_port
*
kmi
=
io
->
driver
;
struct
amba_kmi_port
*
kmi
=
io
->
port_data
;
unsigned
int
divisor
;
int
ret
;
...
...
@@ -105,7 +105,7 @@ static int amba_kmi_open(struct serio *io)
static
void
amba_kmi_close
(
struct
serio
*
io
)
{
struct
amba_kmi_port
*
kmi
=
io
->
driver
;
struct
amba_kmi_port
*
kmi
=
io
->
port_data
;
writeb
(
0
,
KMICR
);
...
...
@@ -117,6 +117,7 @@ static void amba_kmi_close(struct serio *io)
static
int
amba_kmi_probe
(
struct
amba_device
*
dev
,
void
*
id
)
{
struct
amba_kmi_port
*
kmi
;
struct
serio
*
io
;
int
ret
;
ret
=
amba_request_regions
(
dev
,
NULL
);
...
...
@@ -124,21 +125,25 @@ static int amba_kmi_probe(struct amba_device *dev, void *id)
return
ret
;
kmi
=
kmalloc
(
sizeof
(
struct
amba_kmi_port
),
GFP_KERNEL
);
if
(
!
kmi
)
{
io
=
kmalloc
(
sizeof
(
struct
serio
),
GFP_KERNEL
);
if
(
!
kmi
||
!
io
)
{
ret
=
-
ENOMEM
;
goto
out
;
}
memset
(
kmi
,
0
,
sizeof
(
struct
amba_kmi_port
));
kmi
->
io
.
type
=
SERIO_8042
;
kmi
->
io
.
write
=
amba_kmi_write
;
kmi
->
io
.
open
=
amba_kmi_open
;
kmi
->
io
.
close
=
amba_kmi_close
;
kmi
->
io
.
name
=
dev
->
dev
.
bus_id
;
kmi
->
io
.
phys
=
dev
->
dev
.
bus_id
;
kmi
->
io
.
driver
=
kmi
;
memset
(
io
,
0
,
sizeof
(
struct
serio
));
io
->
type
=
SERIO_8042
;
io
->
write
=
amba_kmi_write
;
io
->
open
=
amba_kmi_open
;
io
->
close
=
amba_kmi_close
;
strlcpy
(
io
->
name
,
dev
->
dev
.
bus_id
,
sizeof
(
io
->
name
));
strlcpy
(
io
->
phys
,
dev
->
dev
.
bus_id
,
sizeof
(
io
->
phys
));
io
->
port_data
=
kmi
;
io
->
dev
.
parent
=
&
dev
->
dev
;
kmi
->
io
=
io
;
kmi
->
base
=
ioremap
(
dev
->
res
.
start
,
KMI_SIZE
);
if
(
!
kmi
->
base
)
{
ret
=
-
ENOMEM
;
...
...
@@ -154,13 +159,14 @@ static int amba_kmi_probe(struct amba_device *dev, void *id)
kmi
->
irq
=
dev
->
irq
[
0
];
amba_set_drvdata
(
dev
,
kmi
);
serio_register_port
(
&
kmi
->
io
);
serio_register_port
(
kmi
->
io
);
return
0
;
unmap:
iounmap
(
kmi
->
base
);
out:
kfree
(
kmi
);
kfree
(
io
);
amba_release_regions
(
dev
);
return
ret
;
}
...
...
@@ -171,7 +177,7 @@ static int amba_kmi_remove(struct amba_device *dev)
amba_set_drvdata
(
dev
,
NULL
);
serio_unregister_port
(
&
kmi
->
io
);
serio_unregister_port
(
kmi
->
io
);
clk_put
(
kmi
->
clk
);
iounmap
(
kmi
->
base
);
kfree
(
kmi
);
...
...
@@ -184,7 +190,7 @@ static int amba_kmi_resume(struct amba_device *dev)
struct
amba_kmi_port
*
kmi
=
amba_get_drvdata
(
dev
);
/* kick the serio layer to rescan this port */
serio_re
scan
(
&
kmi
->
io
);
serio_re
connect
(
kmi
->
io
);
return
0
;
}
...
...
@@ -214,7 +220,7 @@ static int __init amba_kmi_init(void)
static
void
__exit
amba_kmi_exit
(
void
)
{
return
amba_driver_unregister
(
&
ambakmi_driver
);
amba_driver_unregister
(
&
ambakmi_driver
);
}
module_init
(
amba_kmi_init
);
...
...
drivers/input/serio/ct82c710.c
View file @
73df7566
...
...
@@ -36,6 +36,7 @@
#include <linux/interrupt.h>
#include <linux/serio.h>
#include <linux/errno.h>
#include <linux/err.h>
#include <asm/io.h>
...
...
@@ -43,9 +44,6 @@ MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
MODULE_DESCRIPTION
(
"82C710 C&T mouse port chip driver"
);
MODULE_LICENSE
(
"GPL"
);
static
char
ct82c710_name
[]
=
"C&T 82c710 mouse port"
;
static
char
ct82c710_phys
[
16
];
/*
* ct82c710 interface
*/
...
...
@@ -61,10 +59,22 @@ static char ct82c710_phys[16];
#define CT82C710_IRQ 12
static
int
ct82c710_data
;
static
int
ct82c710_status
;
#define CT82C710_DATA ct82c710_iores.start
#define CT82C710_STATUS (ct82c710_iores.start + 1)
static
struct
serio
*
ct82c710_port
;
static
struct
platform_device
*
ct82c710_device
;
static
struct
resource
ct82c710_iores
;
/*
* Interrupt handler for the 82C710 mouse port. A character
* is waiting in the 82C710.
*/
static
irqreturn_t
ct82c710_interrupt
(
int
cpl
,
void
*
dev_id
,
struct
pt_regs
*
regs
);
static
irqreturn_t
ct82c710_interrupt
(
int
cpl
,
void
*
dev_id
,
struct
pt_regs
*
regs
)
{
return
serio_interrupt
(
ct82c710_port
,
inb
(
CT82C710_DATA
),
0
,
regs
);
}
/*
* Wait for device to send output char and flush any input char.
...
...
@@ -74,10 +84,10 @@ static int ct82c170_wait(void)
{
int
timeout
=
60000
;
while
((
inb
(
ct82c710_status
)
&
(
CT82C710_RX_FULL
|
CT82C710_TX_IDLE
|
CT82C710_DEV_IDLE
))
while
((
inb
(
CT82C710_STATUS
)
&
(
CT82C710_RX_FULL
|
CT82C710_TX_IDLE
|
CT82C710_DEV_IDLE
))
!=
(
CT82C710_DEV_IDLE
|
CT82C710_TX_IDLE
)
&&
timeout
)
{
if
(
inb_p
(
ct82c710_status
)
&
CT82C710_RX_FULL
)
inb_p
(
ct82c710_data
);
if
(
inb_p
(
CT82C710_STATUS
)
&
CT82C710_RX_FULL
)
inb_p
(
CT82C710_DATA
);
udelay
(
1
);
timeout
--
;
...
...
@@ -91,7 +101,7 @@ static void ct82c710_close(struct serio *serio)
if
(
ct82c170_wait
())
printk
(
KERN_WARNING
"ct82c710.c: Device busy in close()
\n
"
);
outb_p
(
inb_p
(
ct82c710_status
)
&
~
(
CT82C710_ENABLE
|
CT82C710_INTS_ON
),
ct82c710_status
);
outb_p
(
inb_p
(
CT82C710_STATUS
)
&
~
(
CT82C710_ENABLE
|
CT82C710_INTS_ON
),
CT82C710_STATUS
);
if
(
ct82c170_wait
())
printk
(
KERN_WARNING
"ct82c710.c: Device busy in close()
\n
"
);
...
...
@@ -106,21 +116,21 @@ static int ct82c710_open(struct serio *serio)
if
(
request_irq
(
CT82C710_IRQ
,
ct82c710_interrupt
,
0
,
"ct82c710"
,
NULL
))
return
-
1
;
status
=
inb_p
(
ct82c710_status
);
status
=
inb_p
(
CT82C710_STATUS
);
status
|=
(
CT82C710_ENABLE
|
CT82C710_RESET
);
outb_p
(
status
,
ct82c710_status
);
outb_p
(
status
,
CT82C710_STATUS
);
status
&=
~
(
CT82C710_RESET
);
outb_p
(
status
,
ct82c710_status
);
outb_p
(
status
,
CT82C710_STATUS
);
status
|=
CT82C710_INTS_ON
;
outb_p
(
status
,
ct82c710_status
);
/* Enable interrupts */
outb_p
(
status
,
CT82C710_STATUS
);
/* Enable interrupts */
while
(
ct82c170_wait
())
{
printk
(
KERN_ERR
"ct82c710: Device busy in open()
\n
"
);
status
&=
~
(
CT82C710_ENABLE
|
CT82C710_INTS_ON
);
outb_p
(
status
,
ct82c710_status
);
outb_p
(
status
,
CT82C710_STATUS
);
free_irq
(
CT82C710_IRQ
,
NULL
);
return
-
1
;
}
...
...
@@ -135,30 +145,10 @@ static int ct82c710_open(struct serio *serio)
static
int
ct82c710_write
(
struct
serio
*
port
,
unsigned
char
c
)
{
if
(
ct82c170_wait
())
return
-
1
;
outb_p
(
c
,
ct82c710_data
);
outb_p
(
c
,
CT82C710_DATA
);
return
0
;
}
static
struct
serio
ct82c710_port
=
{
.
type
=
SERIO_8042
,
.
name
=
ct82c710_name
,
.
phys
=
ct82c710_phys
,
.
write
=
ct82c710_write
,
.
open
=
ct82c710_open
,
.
close
=
ct82c710_close
,
};
/*
* Interrupt handler for the 82C710 mouse port. A character
* is waiting in the 82C710.
*/
static
irqreturn_t
ct82c710_interrupt
(
int
cpl
,
void
*
dev_id
,
struct
pt_regs
*
regs
)
{
return
serio_interrupt
(
&
ct82c710_port
,
inb
(
ct82c710_data
),
0
,
regs
);
}
/*
* See if we can find a 82C710 device. Read mouse address.
*/
...
...
@@ -175,36 +165,60 @@ static int __init ct82c710_probe(void)
return
-
1
;
/* No: no 82C710 here */
outb_p
(
0x0d
,
0x390
);
/* Write index */
ct82c710_data
=
inb_p
(
0x391
)
<<
2
;
/* Get mouse I/O address */
ct82c710_status
=
ct82c710_data
+
1
;
ct82c710_iores
.
start
=
inb_p
(
0x391
)
<<
2
;
/* Get mouse I/O address */
ct82c710_iores
.
end
=
ct82c710_iores
.
start
+
1
;
ct82c710_iores
.
flags
=
IORESOURCE_IO
;
outb_p
(
0x0f
,
0x390
);
outb_p
(
0x0f
,
0x391
);
/* Close config mode */
return
0
;
}
static
struct
serio
*
__init
ct82c710_allocate_port
(
void
)
{
struct
serio
*
serio
;
serio
=
kmalloc
(
sizeof
(
struct
serio
),
GFP_KERNEL
);
if
(
serio
)
{
memset
(
serio
,
0
,
sizeof
(
struct
serio
));
serio
->
type
=
SERIO_8042
;
serio
->
open
=
ct82c710_open
;
serio
->
close
=
ct82c710_close
;
serio
->
write
=
ct82c710_write
;
serio
->
dev
.
parent
=
&
ct82c710_device
->
dev
;
strlcpy
(
serio
->
name
,
"C&T 82c710 mouse port"
,
sizeof
(
serio
->
name
));
snprintf
(
serio
->
phys
,
sizeof
(
serio
->
phys
),
"isa%04lx/serio0"
,
CT82C710_DATA
);
}
return
serio
;
}
int
__init
ct82c710_init
(
void
)
{
if
(
ct82c710_probe
())
return
-
ENODEV
;
if
(
request_region
(
ct82c710_data
,
2
,
"ct82c710"
))
return
-
EBUSY
;
ct82c710_device
=
platform_device_register_simple
(
"ct82c710"
,
-
1
,
&
ct82c710_iores
,
1
);
if
(
IS_ERR
(
ct82c710_device
))
return
PTR_ERR
(
ct82c710_device
);
sprintf
(
ct82c710_phys
,
"isa%04x/serio0"
,
ct82c710_data
);
if
(
!
(
ct82c710_port
=
ct82c710_allocate_port
()))
{
platform_device_unregister
(
ct82c710_device
);
return
-
ENOMEM
;
}
serio_register_port
(
&
ct82c710_port
);
serio_register_port
(
ct82c710_port
);
printk
(
KERN_INFO
"serio: C&T 82c710 mouse port at %#x irq %d
\n
"
,
ct82c710_data
,
CT82C710_IRQ
);
printk
(
KERN_INFO
"serio: C&T 82c710 mouse port at %#
l
x irq %d
\n
"
,
CT82C710_DATA
,
CT82C710_IRQ
);
return
0
;
}
void
__exit
ct82c710_exit
(
void
)
{
serio_unregister_port
(
&
ct82c710_port
);
release_region
(
ct82c710_data
,
2
);
serio_unregister_port
(
ct82c710_port
);
platform_device_unregister
(
ct82c710_device
);
}
module_init
(
ct82c710_init
);
...
...
drivers/input/serio/gscps2.c
View file @
73df7566
...
...
@@ -91,7 +91,7 @@ static irqreturn_t gscps2_interrupt(int irq, void *dev, struct pt_regs *regs);
struct
gscps2port
{
struct
list_head
node
;
struct
parisc_device
*
padev
;
struct
serio
port
;
struct
serio
*
port
;
spinlock_t
lock
;
char
*
addr
;
u8
act
,
append
;
/* position in buffer[] */
...
...
@@ -100,7 +100,6 @@ struct gscps2port {
u8
str
;
}
buffer
[
BUFFER_SIZE
+
1
];
int
id
;
char
name
[
32
];
};
/*
...
...
@@ -272,7 +271,7 @@ static irqreturn_t gscps2_interrupt(int irq, void *dev, struct pt_regs *regs)
rxflags
=
((
status
&
GSC_STAT_TERR
)
?
SERIO_TIMEOUT
:
0
)
|
((
status
&
GSC_STAT_PERR
)
?
SERIO_PARITY
:
0
);
serio_interrupt
(
&
ps2port
->
port
,
data
,
rxflags
,
regs
);
serio_interrupt
(
ps2port
->
port
,
data
,
rxflags
,
regs
);
}
/* while() */
...
...
@@ -288,7 +287,7 @@ static irqreturn_t gscps2_interrupt(int irq, void *dev, struct pt_regs *regs)
static
int
gscps2_write
(
struct
serio
*
port
,
unsigned
char
data
)
{
struct
gscps2port
*
ps2port
=
port
->
driver
;
struct
gscps2port
*
ps2port
=
port
->
port_data
;
if
(
!
gscps2_writeb_output
(
ps2port
,
data
))
{
printk
(
KERN_DEBUG
PFX
"sending byte %#x failed.
\n
"
,
data
);
...
...
@@ -304,7 +303,7 @@ static int gscps2_write(struct serio *port, unsigned char data)
static
int
gscps2_open
(
struct
serio
*
port
)
{
struct
gscps2port
*
ps2port
=
port
->
driver
;
struct
gscps2port
*
ps2port
=
port
->
port_data
;
gscps2_reset
(
ps2port
);
...
...
@@ -319,7 +318,7 @@ static int gscps2_open(struct serio *port)
static
void
gscps2_close
(
struct
serio
*
port
)
{
struct
gscps2port
*
ps2port
=
port
->
driver
;
struct
gscps2port
*
ps2port
=
port
->
port_data
;
gscps2_enable
(
ps2port
,
DISABLE
);
}
...
...
@@ -343,7 +342,8 @@ static struct serio gscps2_serio_port =
static
int
__init
gscps2_probe
(
struct
parisc_device
*
dev
)
{
struct
gscps2port
*
ps2port
;
struct
gscps2port
*
ps2port
;
struct
serio
*
serio
;
unsigned
long
hpa
=
dev
->
hpa
;
int
ret
;
...
...
@@ -355,34 +355,45 @@ static int __init gscps2_probe(struct parisc_device *dev)
hpa
+=
GSC_DINO_OFFSET
;
ps2port
=
kmalloc
(
sizeof
(
struct
gscps2port
),
GFP_KERNEL
);
if
(
!
ps2port
)
return
-
ENOMEM
;
serio
=
kmalloc
(
sizeof
(
struct
serio
),
GFP_KERNEL
);
if
(
!
ps2port
||
!
serio
)
{
ret
=
-
ENOMEM
;
goto
fail_nomem
;
}
dev_set_drvdata
(
&
dev
->
dev
,
ps2port
);
memset
(
ps2port
,
0
,
sizeof
(
struct
gscps2port
));
memset
(
serio
,
0
,
sizeof
(
struct
serio
));
ps2port
->
port
=
serio
;
ps2port
->
padev
=
dev
;
ps2port
->
addr
=
ioremap
(
hpa
,
GSC_STATUS
+
4
);
spin_lock_init
(
&
ps2port
->
lock
);
gscps2_reset
(
ps2port
);
ps2port
->
id
=
readb
(
ps2port
->
addr
+
GSC_ID
)
&
0x0f
;
snprintf
(
ps2port
->
name
,
sizeof
(
ps2port
->
name
)
-
1
,
"%s %s"
,
gscps2_serio_port
.
name
,
(
ps2port
->
id
==
GSC_ID_KEYBOARD
)
?
"keyboard"
:
"mouse"
);
memcpy
(
&
ps2port
->
port
,
&
gscps2_serio_port
,
sizeof
(
gscps2_serio_port
));
ps2port
->
port
.
driver
=
ps2port
;
ps2port
->
port
.
name
=
ps2port
->
name
;
ps2port
->
port
.
phys
=
dev
->
dev
.
bus_id
;
ps2port
->
id
=
readb
(
ps2port
->
addr
+
GSC_ID
)
&
0x0f
;
snprintf
(
serio
->
name
,
sizeof
(
serio
->
name
),
"GSC PS/2 %s"
,
(
ps2port
->
id
==
GSC_ID_KEYBOARD
)
?
"keyboard"
:
"mouse"
);
strlcpy
(
serio
->
phys
,
dev
->
dev
.
bus_id
,
sizeof
(
serio
->
phys
));
serio
->
idbus
=
BUS_GSC
;
serio
->
idvendor
=
PCI_VENDOR_ID_HP
;
serio
->
idproduct
=
0x0001
;
serio
->
idversion
=
0x0010
;
serio
->
type
=
SERIO_8042
;
serio
->
write
=
gscps2_write
;
serio
->
open
=
gscps2_open
;
serio
->
close
=
gscps2_close
;
serio
->
port_data
=
ps2port
;
serio
->
dev
.
parent
=
&
dev
->
dev
;
list_add_tail
(
&
ps2port
->
node
,
&
ps2port_list
);
ret
=
-
EBUSY
;
if
(
request_irq
(
dev
->
irq
,
gscps2_interrupt
,
SA_SHIRQ
,
ps2port
->
name
,
ps2port
))
if
(
request_irq
(
dev
->
irq
,
gscps2_interrupt
,
SA_SHIRQ
,
ps2port
->
port
->
name
,
ps2port
))
goto
fail_miserably
;
if
(
(
ps2port
->
id
!=
GSC_ID_KEYBOARD
)
&&
(
ps2port
->
id
!=
GSC_ID_MOUSE
)
)
{
if
(
ps2port
->
id
!=
GSC_ID_KEYBOARD
&&
ps2port
->
id
!=
GSC_ID_MOUSE
)
{
printk
(
KERN_WARNING
PFX
"Unsupported PS/2 port at 0x%08lx (id=%d) ignored
\n
"
,
hpa
,
ps2port
->
id
);
ret
=
-
ENODEV
;
...
...
@@ -395,12 +406,12 @@ static int __init gscps2_probe(struct parisc_device *dev)
#endif
printk
(
KERN_INFO
"serio: %s port at 0x%p irq %d @ %s
\n
"
,
ps2port
->
name
,
ps2port
->
port
->
name
,
ps2port
->
addr
,
ps2port
->
padev
->
irq
,
ps2port
->
port
.
phys
);
ps2port
->
port
->
phys
);
serio_register_port
(
&
ps2port
->
port
);
serio_register_port
(
ps2port
->
port
);
return
0
;
...
...
@@ -411,7 +422,10 @@ static int __init gscps2_probe(struct parisc_device *dev)
list_del
(
&
ps2port
->
node
);
iounmap
(
ps2port
->
addr
);
release_mem_region
(
dev
->
hpa
,
GSC_STATUS
+
4
);
fail_nomem:
kfree
(
ps2port
);
kfree
(
serio
);
return
ret
;
}
...
...
@@ -424,7 +438,7 @@ static int __devexit gscps2_remove(struct parisc_device *dev)
{
struct
gscps2port
*
ps2port
=
dev_get_drvdata
(
&
dev
->
dev
);
serio_unregister_port
(
&
ps2port
->
port
);
serio_unregister_port
(
ps2port
->
port
);
free_irq
(
dev
->
irq
,
ps2port
);
gscps2_flush
(
ps2port
);
list_del
(
&
ps2port
->
node
);
...
...
drivers/input/serio/i8042-io.h
View file @
73df7566
...
...
@@ -65,6 +65,31 @@ static inline void i8042_write_command(int val)
return
;
}
#if defined(__i386__)
#include <linux/dmi.h>
static
struct
dmi_system_id
__initdata
i8042_dmi_table
[]
=
{
{
.
ident
=
"Compaq Proliant 8500"
,
.
matches
=
{
DMI_MATCH
(
DMI_SYS_VENDOR
,
"Compaq"
),
DMI_MATCH
(
DMI_PRODUCT_NAME
,
"ProLiant"
),
DMI_MATCH
(
DMI_PRODUCT_VERSION
,
"8500"
),
},
},
{
.
ident
=
"Compaq Proliant DL760"
,
.
matches
=
{
DMI_MATCH
(
DMI_SYS_VENDOR
,
"Compaq"
),
DMI_MATCH
(
DMI_PRODUCT_NAME
,
"ProLiant"
),
DMI_MATCH
(
DMI_PRODUCT_VERSION
,
"DL760"
),
},
},
{
}
};
#endif
static
inline
int
i8042_platform_init
(
void
)
{
/*
...
...
@@ -79,6 +104,12 @@ static inline int i8042_platform_init(void)
#if !defined(__i386__) && !defined(__x86_64__)
i8042_reset
=
1
;
#endif
#if defined(__i386__)
if
(
dmi_check_system
(
i8042_dmi_table
))
i8042_noloop
=
1
;
#endif
return
0
;
}
...
...
drivers/input/serio/i8042.c
View file @
73df7566
/*
* i8042 keyboard and mouse controller driver for Linux
*
* Copyright (c) 1999-200
2
Vojtech Pavlik
* Copyright (c) 1999-200
4
Vojtech Pavlik
*/
/*
...
...
@@ -21,6 +21,7 @@
#include <linux/sysdev.h>
#include <linux/pm.h>
#include <linux/serio.h>
#include <linux/err.h>
#include <asm/io.h>
...
...
@@ -52,6 +53,10 @@ static unsigned int i8042_dumbkbd;
module_param_named
(
dumbkbd
,
i8042_dumbkbd
,
bool
,
0
);
MODULE_PARM_DESC
(
dumbkbd
,
"Pretend that controller can only read data from keyboard"
);
static
unsigned
int
i8042_noloop
;
module_param_named
(
noloop
,
i8042_noloop
,
bool
,
0
);
MODULE_PARM_DESC
(
dumbkbd
,
"Disable the AUX Loopback command while probing for the AUX port"
);
__obsolete_setup
(
"i8042_noaux"
);
__obsolete_setup
(
"i8042_nomux"
);
__obsolete_setup
(
"i8042_unlock"
);
...
...
@@ -70,19 +75,35 @@ struct i8042_values {
unsigned
char
irqen
;
unsigned
char
exists
;
signed
char
mux
;
unsigned
char
*
name
;
unsigned
char
*
phys
;
char
name
[
8
];
};
static
struct
i8042_values
i8042_kbd_values
=
{
.
disable
=
I8042_CTR_KBDDIS
,
.
irqen
=
I8042_CTR_KBDINT
,
.
mux
=
-
1
,
.
name
=
"KBD"
,
};
static
struct
i8042_values
i8042_aux_values
=
{
.
disable
=
I8042_CTR_AUXDIS
,
.
irqen
=
I8042_CTR_AUXINT
,
.
mux
=
-
1
,
.
name
=
"AUX"
,
};
static
struct
serio
i8042_kbd_port
;
static
struct
serio
i8042_aux_port
;
static
struct
i8042_values
i8042_mux_values
[
I8042_NUM_MUX_PORTS
];
static
struct
serio
*
i8042_kbd_port
;
static
struct
serio
*
i8042_aux_port
;
static
struct
serio
*
i8042_mux_port
[
I8042_NUM_MUX_PORTS
];
static
unsigned
char
i8042_initial_ctr
;
static
unsigned
char
i8042_ctr
;
static
unsigned
char
i8042_mux_open
;
static
unsigned
char
i8042_mux_present
;
static
unsigned
char
i8042_sysdev_initialized
;
static
struct
pm_dev
*
i8042_pm_dev
;
struct
timer_list
i8042_timer
;
static
struct
timer_list
i8042_timer
;
static
struct
platform_device
*
i8042_platform_device
;
/*
* Shared IRQ's require a device pointer, but this driver doesn't support
...
...
@@ -95,6 +116,7 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id, struct pt_regs *regs);
/*
* The i8042_wait_read() and i8042_wait_write functions wait for the i8042 to
* be ready for reading values from it / writing values to it.
* Called always with i8042_lock held.
*/
static
int
i8042_wait_read
(
void
)
...
...
@@ -131,6 +153,7 @@ static int i8042_flush(void)
spin_lock_irqsave
(
&
i8042_lock
,
flags
);
while
((
i8042_read_status
()
&
I8042_STR_OBF
)
&&
(
i
++
<
I8042_BUFFER_SIZE
))
{
udelay
(
50
);
data
=
i8042_read_data
();
dbg
(
"%02x <- i8042 (flush, %s)"
,
data
,
i8042_read_status
()
&
I8042_STR_AUXDATA
?
"aux"
:
"kbd"
);
...
...
@@ -154,6 +177,9 @@ static int i8042_command(unsigned char *param, int command)
unsigned
long
flags
;
int
retval
=
0
,
i
=
0
;
if
(
i8042_noloop
&&
command
==
I8042_CMD_AUX_LOOP
)
return
-
1
;
spin_lock_irqsave
(
&
i8042_lock
,
flags
);
retval
=
i8042_wait_write
();
...
...
@@ -214,7 +240,7 @@ static int i8042_kbd_write(struct serio *port, unsigned char c)
static
int
i8042_aux_write
(
struct
serio
*
port
,
unsigned
char
c
)
{
struct
i8042_values
*
values
=
port
->
driver
;
struct
i8042_values
*
values
=
port
->
port_data
;
int
retval
;
/*
...
...
@@ -242,7 +268,7 @@ static int i8042_aux_write(struct serio *port, unsigned char c)
static
int
i8042_activate_port
(
struct
serio
*
port
)
{
struct
i8042_values
*
values
=
port
->
driver
;
struct
i8042_values
*
values
=
port
->
port_data
;
i8042_flush
();
...
...
@@ -270,7 +296,7 @@ static int i8042_activate_port(struct serio *port)
static
int
i8042_open
(
struct
serio
*
port
)
{
struct
i8042_values
*
values
=
port
->
driver
;
struct
i8042_values
*
values
=
port
->
port_data
;
if
(
values
->
mux
!=
-
1
)
if
(
i8042_mux_open
++
)
...
...
@@ -309,7 +335,7 @@ static int i8042_open(struct serio *port)
static
void
i8042_close
(
struct
serio
*
port
)
{
struct
i8042_values
*
values
=
port
->
driver
;
struct
i8042_values
*
values
=
port
->
port_data
;
if
(
values
->
mux
!=
-
1
)
if
(
--
i8042_mux_open
)
...
...
@@ -327,52 +353,6 @@ static void i8042_close(struct serio *port)
i8042_flush
();
}
/*
* Structures for registering the devices in the serio.c module.
*/
static
struct
i8042_values
i8042_kbd_values
=
{
.
irqen
=
I8042_CTR_KBDINT
,
.
disable
=
I8042_CTR_KBDDIS
,
.
name
=
"KBD"
,
.
mux
=
-
1
,
};
static
struct
serio
i8042_kbd_port
=
{
.
type
=
SERIO_8042_XL
,
.
write
=
i8042_kbd_write
,
.
open
=
i8042_open
,
.
close
=
i8042_close
,
.
driver
=
&
i8042_kbd_values
,
.
name
=
"i8042 Kbd Port"
,
.
phys
=
I8042_KBD_PHYS_DESC
,
};
static
struct
i8042_values
i8042_aux_values
=
{
.
irqen
=
I8042_CTR_AUXINT
,
.
disable
=
I8042_CTR_AUXDIS
,
.
name
=
"AUX"
,
.
mux
=
-
1
,
};
static
struct
serio
i8042_aux_port
=
{
.
type
=
SERIO_8042
,
.
write
=
i8042_aux_write
,
.
open
=
i8042_open
,
.
close
=
i8042_close
,
.
driver
=
&
i8042_aux_values
,
.
name
=
"i8042 Aux Port"
,
.
phys
=
I8042_AUX_PHYS_DESC
,
};
static
struct
i8042_values
i8042_mux_values
[
4
];
static
struct
serio
i8042_mux_port
[
4
];
static
char
i8042_mux_names
[
4
][
32
];
static
char
i8042_mux_short
[
4
][
16
];
static
char
i8042_mux_phys
[
4
][
32
];
/*
* i8042_interrupt() is the most important function in this driver -
* it handles the interrupts from the i8042, and sends incoming bytes
...
...
@@ -384,6 +364,7 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id, struct pt_regs *regs)
unsigned
long
flags
;
unsigned
char
str
,
data
=
0
;
unsigned
int
dfl
;
unsigned
int
aux_idx
;
int
ret
;
mod_timer
(
&
i8042_timer
,
jiffies
+
I8042_POLL_PERIOD
);
...
...
@@ -400,44 +381,67 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id, struct pt_regs *regs)
goto
out
;
}
dfl
=
((
str
&
I8042_STR_PARITY
)
?
SERIO_PARITY
:
0
)
|
((
str
&
I8042_STR_TIMEOUT
)
?
SERIO_TIMEOUT
:
0
);
if
(
i8042_mux_values
[
0
].
exists
&&
(
str
&
I8042_STR_AUXDATA
))
{
if
(
i8042_mux_present
&&
(
str
&
I8042_STR_AUXDATA
))
{
static
unsigned
long
last_transmit
;
static
unsigned
char
last_str
;
dfl
=
0
;
if
(
str
&
I8042_STR_MUXERR
)
{
dbg
(
"MUX error, status is %02x, data is %02x"
,
str
,
data
);
switch
(
data
)
{
default:
/*
* When MUXERR condition is signalled the data register can only contain
* 0xfd, 0xfe or 0xff if implementation follows the spec. Unfortunately
* it is not always the case. Some KBC just get confused which port the
* data came from and signal error leaving the data intact. They _do not_
* revert to legacy mode (actually I've never seen KBC reverting to legacy
* mode yet, when we see one we'll add proper handling).
* Anyway, we will assume that the data came from the same serio last byte
* was transmitted (if transmission happened not too long ago).
*/
if
(
time_before
(
jiffies
,
last_transmit
+
HZ
/
10
))
{
str
=
last_str
;
break
;
}
/* fall through - report timeout */
case
0xfd
:
case
0xfe
:
dfl
=
SERIO_TIMEOUT
;
break
;
case
0xff
:
dfl
=
SERIO_PARITY
;
break
;
case
0xfe
:
dfl
=
SERIO_TIMEOUT
;
data
=
0xfe
;
break
;
case
0xff
:
dfl
=
SERIO_PARITY
;
data
=
0xfe
;
break
;
}
data
=
0xfe
;
}
else
dfl
=
0
;
}
aux_idx
=
(
str
>>
6
)
&
3
;
dbg
(
"%02x <- i8042 (interrupt, aux%d, %d%s%s)"
,
data
,
(
str
>>
6
)
,
irq
,
data
,
aux_idx
,
irq
,
dfl
&
SERIO_PARITY
?
", bad parity"
:
""
,
dfl
&
SERIO_TIMEOUT
?
", timeout"
:
""
);
serio_interrupt
(
i8042_mux_port
+
((
str
>>
6
)
&
3
),
data
,
dfl
,
regs
);
if
(
likely
(
i8042_mux_values
[
aux_idx
].
exists
))
serio_interrupt
(
i8042_mux_port
[
aux_idx
],
data
,
dfl
,
regs
);
last_str
=
str
;
last_transmit
=
jiffies
;
goto
irq_ret
;
}
dfl
=
((
str
&
I8042_STR_PARITY
)
?
SERIO_PARITY
:
0
)
|
((
str
&
I8042_STR_TIMEOUT
)
?
SERIO_TIMEOUT
:
0
);
dbg
(
"%02x <- i8042 (interrupt, %s, %d%s%s)"
,
data
,
(
str
&
I8042_STR_AUXDATA
)
?
"aux"
:
"kbd"
,
irq
,
dfl
&
SERIO_PARITY
?
", bad parity"
:
""
,
dfl
&
SERIO_TIMEOUT
?
", timeout"
:
""
);
if
(
i8042_aux_values
.
exists
&&
(
str
&
I8042_STR_AUXDATA
))
{
serio_interrupt
(
&
i8042_aux_port
,
data
,
dfl
,
regs
);
goto
irq_ret
;
}
if
(
!
i8042_kbd_values
.
exists
)
goto
irq_ret
;
serio_interrupt
(
&
i8042_kbd_port
,
data
,
dfl
,
regs
);
if
(
str
&
I8042_STR_AUXDATA
)
{
if
(
likely
(
i8042_aux_values
.
exists
))
serio_interrupt
(
i8042_aux_port
,
data
,
dfl
,
regs
);
}
else
{
if
(
likely
(
i8042_kbd_values
.
exists
))
serio_interrupt
(
i8042_kbd_port
,
data
,
dfl
,
regs
);
}
irq_ret:
ret
=
1
;
...
...
@@ -474,17 +478,8 @@ static int i8042_enable_mux_mode(struct i8042_values *values, unsigned char *mux
if
(
i8042_command
(
&
param
,
I8042_CMD_AUX_LOOP
)
||
param
!=
0xa9
)
return
-
1
;
param
=
0xa4
;
if
(
i8042_command
(
&
param
,
I8042_CMD_AUX_LOOP
)
||
param
==
0x5b
)
{
/*
* Do another loop test with the 0x5a value. Doing anything else upsets
* Profusion/ServerWorks OSB4 chipsets.
*/
param
=
0x5a
;
i8042_command
(
&
param
,
I8042_CMD_AUX_LOOP
);
if
(
i8042_command
(
&
param
,
I8042_CMD_AUX_LOOP
)
||
param
==
0x5b
)
return
-
1
;
}
if
(
mux_version
)
*
mux_version
=
~
param
;
...
...
@@ -639,8 +634,10 @@ static int __init i8042_check_aux(struct i8042_values *values)
* registers it, and reports to the user.
*/
static
int
__init
i8042_port_register
(
struct
i8042_values
*
values
,
struct
serio
*
port
)
static
int
__init
i8042_port_register
(
struct
serio
*
port
)
{
struct
i8042_values
*
values
=
port
->
port_data
;
values
->
exists
=
1
;
i8042_ctr
&=
~
values
->
disable
;
...
...
@@ -677,6 +674,7 @@ static void i8042_timer_func(unsigned long data)
static
int
i8042_controller_init
(
void
)
{
unsigned
long
flags
;
/*
* Test the i8042. We need to know if it thinks it's working correctly
...
...
@@ -723,12 +721,14 @@ static int i8042_controller_init(void)
* Handle keylock.
*/
spin_lock_irqsave
(
&
i8042_lock
,
flags
);
if
(
~
i8042_read_status
()
&
I8042_STR_KEYLOCK
)
{
if
(
i8042_unlock
)
i8042_ctr
|=
I8042_CTR_IGNKEYLOCK
;
else
printk
(
KERN_WARNING
"i8042.c: Warning: Keylock active.
\n
"
);
}
spin_unlock_irqrestore
(
&
i8042_lock
,
flags
);
/*
* If the chip is configured into nontranslated mode by the BIOS, don't
...
...
@@ -745,10 +745,8 @@ static int i8042_controller_init(void)
* BIOSes.
*/
if
(
i8042_direct
)
{
if
(
i8042_direct
)
i8042_ctr
&=
~
I8042_CTR_XLATE
;
i8042_kbd_port
.
type
=
SERIO_8042
;
}
/*
* Write CTR back.
...
...
@@ -802,14 +800,14 @@ void i8042_controller_cleanup(void)
*/
if
(
i8042_kbd_values
.
exists
)
serio_cleanup
(
&
i8042_kbd_port
);
serio_cleanup
(
i8042_kbd_port
);
if
(
i8042_aux_values
.
exists
)
serio_cleanup
(
&
i8042_aux_port
);
serio_cleanup
(
i8042_aux_port
);
for
(
i
=
0
;
i
<
4
;
i
++
)
for
(
i
=
0
;
i
<
I8042_NUM_MUX_PORTS
;
i
++
)
if
(
i8042_mux_values
[
i
].
exists
)
serio_cleanup
(
i8042_mux_port
+
i
);
serio_cleanup
(
i8042_mux_port
[
i
]
);
i8042_controller_reset
();
}
...
...
@@ -851,15 +849,15 @@ static int i8042_controller_resume(void)
* Reconnect anything that was connected to the ports.
*/
if
(
i8042_kbd_values
.
exists
&&
i8042_activate_port
(
&
i8042_kbd_port
)
==
0
)
serio_reconnect
(
&
i8042_kbd_port
);
if
(
i8042_kbd_values
.
exists
&&
i8042_activate_port
(
i8042_kbd_port
)
==
0
)
serio_reconnect
(
i8042_kbd_port
);
if
(
i8042_aux_values
.
exists
&&
i8042_activate_port
(
&
i8042_aux_port
)
==
0
)
serio_reconnect
(
&
i8042_aux_port
);
if
(
i8042_aux_values
.
exists
&&
i8042_activate_port
(
i8042_aux_port
)
==
0
)
serio_reconnect
(
i8042_aux_port
);
for
(
i
=
0
;
i
<
4
;
i
++
)
if
(
i8042_mux_values
[
i
].
exists
&&
i8042_activate_port
(
i8042_mux_port
+
i
)
==
0
)
serio_reconnect
(
i8042_mux_port
+
i
);
for
(
i
=
0
;
i
<
I8042_NUM_MUX_PORTS
;
i
++
)
if
(
i8042_mux_values
[
i
].
exists
&&
i8042_activate_port
(
i8042_mux_port
[
i
]
)
==
0
)
serio_reconnect
(
i8042_mux_port
[
i
]
);
/*
* Restart timer (for polling "stuck" data)
*/
...
...
@@ -882,7 +880,7 @@ static int i8042_notify_sys(struct notifier_block *this, unsigned long code,
return
NOTIFY_DONE
;
}
static
struct
notifier_block
i8042_notifier
=
static
struct
notifier_block
i8042_notifier
=
{
i8042_notify_sys
,
NULL
,
...
...
@@ -892,25 +890,27 @@ static struct notifier_block i8042_notifier=
/*
* Suspend/resume handlers for the new PM scheme (driver model)
*/
static
int
i8042_suspend
(
struct
sys_device
*
dev
,
u32
state
)
static
int
i8042_suspend
(
struct
device
*
dev
,
u32
state
,
u32
level
)
{
return
i8042_controller_suspend
()
;
return
level
==
SUSPEND_DISABLE
?
i8042_controller_suspend
()
:
0
;
}
static
int
i8042_resume
(
struct
sys_device
*
dev
)
static
int
i8042_resume
(
struct
device
*
dev
,
u32
level
)
{
return
i8042_controller_resume
()
;
return
level
==
RESUME_ENABLE
?
i8042_controller_resume
()
:
0
;
}
static
struct
sysdev_class
kbc_sysclass
=
{
set_kset_name
(
"i8042"
),
.
suspend
=
i8042_suspend
,
.
resume
=
i8042_resume
,
};
static
void
i8042_shutdown
(
struct
device
*
dev
)
{
i8042_controller_cleanup
();
}
static
struct
sys_device
device_i8042
=
{
.
id
=
0
,
.
cls
=
&
kbc_sysclass
,
static
struct
device_driver
i8042_driver
=
{
.
name
=
"i8042"
,
.
bus
=
&
platform_bus_type
,
.
suspend
=
i8042_suspend
,
.
resume
=
i8042_resume
,
.
shutdown
=
i8042_shutdown
,
};
/*
...
...
@@ -929,23 +929,75 @@ static int i8042_pm_callback(struct pm_dev *dev, pm_request_t request, void *dum
return
0
;
}
static
void
__init
i8042_init_mux_values
(
struct
i8042_values
*
values
,
struct
serio
*
port
,
int
index
)
static
struct
serio
*
__init
i8042_allocate_kbd_port
(
void
)
{
struct
serio
*
serio
;
serio
=
kmalloc
(
sizeof
(
struct
serio
),
GFP_KERNEL
);
if
(
serio
)
{
memset
(
serio
,
0
,
sizeof
(
struct
serio
));
serio
->
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
->
port_data
=
&
i8042_kbd_values
,
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
));
}
return
serio
;
}
static
struct
serio
*
__init
i8042_allocate_aux_port
(
void
)
{
memcpy
(
port
,
&
i8042_aux_port
,
sizeof
(
struct
serio
));
memcpy
(
values
,
&
i8042_aux_values
,
sizeof
(
struct
i8042_values
));
sprintf
(
i8042_mux_names
[
index
],
"i8042 Aux-%d Port"
,
index
);
sprintf
(
i8042_mux_phys
[
index
],
I8042_MUX_PHYS_DESC
,
index
+
1
);
sprintf
(
i8042_mux_short
[
index
],
"AUX%d"
,
index
);
port
->
name
=
i8042_mux_names
[
index
];
port
->
phys
=
i8042_mux_phys
[
index
];
port
->
driver
=
values
;
values
->
name
=
i8042_mux_short
[
index
];
values
->
mux
=
index
;
struct
serio
*
serio
;
serio
=
kmalloc
(
sizeof
(
struct
serio
),
GFP_KERNEL
);
if
(
serio
)
{
memset
(
serio
,
0
,
sizeof
(
struct
serio
));
serio
->
type
=
SERIO_8042
;
serio
->
write
=
i8042_aux_write
;
serio
->
open
=
i8042_open
;
serio
->
close
=
i8042_close
;
serio
->
port_data
=
&
i8042_aux_values
,
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
));
}
return
serio
;
}
static
struct
serio
*
__init
i8042_allocate_mux_port
(
int
index
)
{
struct
serio
*
serio
;
struct
i8042_values
*
values
=
&
i8042_mux_values
[
index
];
serio
=
kmalloc
(
sizeof
(
struct
serio
),
GFP_KERNEL
);
if
(
serio
)
{
*
values
=
i8042_aux_values
;
snprintf
(
values
->
name
,
sizeof
(
values
->
name
),
"AUX%d"
,
index
);
values
->
mux
=
index
;
memset
(
serio
,
0
,
sizeof
(
struct
serio
));
serio
->
type
=
SERIO_8042
;
serio
->
write
=
i8042_aux_write
;
serio
->
open
=
i8042_open
;
serio
->
close
=
i8042_close
;
serio
->
port_data
=
values
;
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
);
}
return
serio
;
}
int
__init
i8042_init
(
void
)
{
int
i
;
int
err
;
dbg_init
();
...
...
@@ -961,30 +1013,36 @@ int __init i8042_init(void)
if
(
i8042_controller_init
())
return
-
ENODEV
;
if
(
i8042_dumbkbd
)
i8042_kbd_port
.
write
=
NULL
;
err
=
driver_register
(
&
i8042_driver
);
if
(
err
)
return
err
;
i8042_platform_device
=
platform_device_register_simple
(
"i8042"
,
-
1
,
NULL
,
0
);
if
(
IS_ERR
(
i8042_platform_device
))
{
driver_unregister
(
&
i8042_driver
);
return
PTR_ERR
(
i8042_platform_device
);
}
if
(
!
i8042_noaux
&&
!
i8042_check_aux
(
&
i8042_aux_values
))
{
if
(
!
i8042_nomux
&&
!
i8042_check_mux
(
&
i8042_aux_values
))
for
(
i
=
0
;
i
<
4
;
i
++
)
{
i8042_init_mux_values
(
i8042_mux_values
+
i
,
i8042_mux_port
+
i
,
i
);
i8042_port_register
(
i8042_mux_values
+
i
,
i8042_mux_port
+
i
);
for
(
i
=
0
;
i
<
I8042_NUM_MUX_PORTS
;
i
++
)
{
i8042_mux_port
[
i
]
=
i8042_allocate_mux_port
(
i
);
if
(
i8042_mux_port
[
i
])
i8042_port_register
(
i8042_mux_port
[
i
]);
}
else
i8042_port_register
(
&
i8042_aux_values
,
&
i8042_aux_port
);
else
{
i8042_aux_port
=
i8042_allocate_aux_port
();
if
(
i8042_aux_port
)
i8042_port_register
(
i8042_aux_port
);
}
}
i8042_port_register
(
&
i8042_kbd_values
,
&
i8042_kbd_port
);
i8042_kbd_port
=
i8042_allocate_kbd_port
();
if
(
i8042_kbd_port
)
i8042_port_register
(
i8042_kbd_port
);
mod_timer
(
&
i8042_timer
,
jiffies
+
I8042_POLL_PERIOD
);
if
(
sysdev_class_register
(
&
kbc_sysclass
)
==
0
)
{
if
(
sysdev_register
(
&
device_i8042
)
==
0
)
i8042_sysdev_initialized
=
1
;
else
sysdev_class_unregister
(
&
kbc_sysclass
);
}
i8042_pm_dev
=
pm_register
(
PM_SYS_DEV
,
PM_SYS_UNKNOWN
,
i8042_pm_callback
);
register_reboot_notifier
(
&
i8042_notifier
);
...
...
@@ -1001,24 +1059,23 @@ void __exit i8042_exit(void)
if
(
i8042_pm_dev
)
pm_unregister
(
i8042_pm_dev
);
if
(
i8042_sysdev_initialized
)
{
sysdev_unregister
(
&
device_i8042
);
sysdev_class_unregister
(
&
kbc_sysclass
);
}
i8042_controller_cleanup
();
if
(
i8042_kbd_values
.
exists
)
serio_unregister_port
(
&
i8042_kbd_port
);
serio_unregister_port
(
i8042_kbd_port
);
if
(
i8042_aux_values
.
exists
)
serio_unregister_port
(
&
i8042_aux_port
);
serio_unregister_port
(
i8042_aux_port
);
for
(
i
=
0
;
i
<
4
;
i
++
)
for
(
i
=
0
;
i
<
I8042_NUM_MUX_PORTS
;
i
++
)
if
(
i8042_mux_values
[
i
].
exists
)
serio_unregister_port
(
i8042_mux_port
+
i
);
serio_unregister_port
(
i8042_mux_port
[
i
]);
del_timer_sync
(
&
i8042_timer
);
platform_device_unregister
(
i8042_platform_device
);
driver_unregister
(
&
i8042_driver
);
i8042_platform_exit
();
}
...
...
drivers/input/serio/i8042.h
View file @
73df7566
...
...
@@ -103,6 +103,13 @@
#define I8042_BUFFER_SIZE 32
/*
* Number of AUX ports on controllers supporting active multiplexing
* specification
*/
#define I8042_NUM_MUX_PORTS 4
/*
* Debug.
*/
...
...
drivers/input/serio/maceps2.c
View file @
73df7566
...
...
@@ -17,6 +17,7 @@
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/err.h>
#include <asm/io.h>
#include <asm/irq.h>
...
...
@@ -46,15 +47,18 @@ MODULE_LICENSE("GPL");
#define PS2_CONTROL_RX_CLOCK_ENABLE BIT(4)
/* pause reception if set to 0 */
#define PS2_CONTROL_RESET BIT(5)
/* reset */
struct
maceps2_data
{
struct
mace_ps2port
*
port
;
int
irq
;
};
static
struct
maceps2_data
port_data
[
2
];
static
struct
serio
*
maceps2_port
[
2
];
static
struct
platform_device
*
maceps2_device
;
static
int
maceps2_write
(
struct
serio
*
dev
,
unsigned
char
val
)
{
struct
mace_ps2port
*
port
=
((
struct
maceps2_data
*
)
dev
->
driver
)
->
port
;
struct
mace_ps2port
*
port
=
((
struct
maceps2_data
*
)
dev
->
port_data
)
->
port
;
unsigned
int
timeout
=
MACE_PS2_TIMEOUT
;
do
{
...
...
@@ -68,11 +72,10 @@ static int maceps2_write(struct serio *dev, unsigned char val)
return
-
1
;
}
static
irqreturn_t
maceps2_interrupt
(
int
irq
,
void
*
dev_id
,
struct
pt_regs
*
regs
)
static
irqreturn_t
maceps2_interrupt
(
int
irq
,
void
*
dev_id
,
struct
pt_regs
*
regs
)
{
struct
serio
*
dev
=
dev_id
;
struct
mace_ps2port
*
port
=
((
struct
maceps2_data
*
)
dev
->
driver
)
->
port
;
struct
mace_ps2port
*
port
=
((
struct
maceps2_data
*
)
dev
->
port_data
)
->
port
;
unsigned
int
byte
;
if
(
mace_read
(
port
->
status
)
&
PS2_STATUS_RX_FULL
)
{
...
...
@@ -85,7 +88,7 @@ static irqreturn_t maceps2_interrupt(int irq, void *dev_id,
static
int
maceps2_open
(
struct
serio
*
dev
)
{
struct
maceps2_data
*
data
=
(
struct
maceps2_data
*
)
dev
->
driver
;
struct
maceps2_data
*
data
=
(
struct
maceps2_data
*
)
dev
->
port_data
;
if
(
request_irq
(
data
->
irq
,
maceps2_interrupt
,
0
,
"PS/2 port"
,
dev
))
{
printk
(
KERN_ERR
"Could not allocate PS/2 IRQ
\n
"
);
...
...
@@ -106,7 +109,7 @@ static int maceps2_open(struct serio *dev)
static
void
maceps2_close
(
struct
serio
*
dev
)
{
struct
maceps2_data
*
data
=
(
struct
maceps2_data
*
)
dev
->
driver
;
struct
maceps2_data
*
data
=
(
struct
maceps2_data
*
)
dev
->
port_data
;
mace_write
(
PS2_CONTROL_TX_CLOCK_DISABLE
|
PS2_CONTROL_RESET
,
data
->
port
->
control
);
...
...
@@ -114,46 +117,59 @@ static void maceps2_close(struct serio *dev)
free_irq
(
data
->
irq
,
dev
);
}
static
struct
maceps2_data
port0_data
,
port1_data
;
static
struct
serio
maceps2_port0
=
static
struct
serio
*
__init
maceps2_allocate_port
(
int
idx
)
{
.
type
=
SERIO_8042
,
.
open
=
maceps2_open
,
.
close
=
maceps2_close
,
.
write
=
maceps2_write
,
.
name
=
"MACE PS/2 port0"
,
.
phys
=
"mace/serio0"
,
.
driver
=
&
port0_data
,
};
struct
serio
*
serio
;
serio
=
kmalloc
(
sizeof
(
struct
serio
),
GFP_KERNEL
);
if
(
serio
)
{
memset
(
serio
,
0
,
sizeof
(
struct
serio
));
serio
->
type
=
SERIO_8042
;
serio
->
write
=
maceps2_write
;
serio
->
open
=
maceps2_open
;
serio
->
close
=
maceps2_close
;
snprintf
(
serio
->
name
,
sizeof
(
serio
->
name
),
"MACE PS/2 port%d"
,
idx
);
snprintf
(
serio
->
phys
,
sizeof
(
serio
->
phys
),
"mace/serio%d"
,
idx
);
serio
->
port_data
=
&
port_data
[
idx
];
serio
->
dev
.
parent
=
&
maceps2_device
->
dev
;
}
return
serio
;
}
static
struct
serio
maceps2_port1
=
{
.
type
=
SERIO_8042
,
.
open
=
maceps2_open
,
.
close
=
maceps2_close
,
.
write
=
maceps2_write
,
.
name
=
"MACE PS/2 port1"
,
.
phys
=
"mace/serio1"
,
.
driver
=
&
port1_data
,
};
static
int
__init
maceps2_init
(
void
)
{
port0_data
.
port
=
&
mace
->
perif
.
ps2
.
keyb
;
port0_data
.
irq
=
MACEISA_KEYB_IRQ
;
port1_data
.
port
=
&
mace
->
perif
.
ps2
.
mouse
;
port1_data
.
irq
=
MACEISA_MOUSE_IRQ
;
serio_register_port
(
&
maceps2_port0
);
serio_register_port
(
&
maceps2_port1
);
maceps2_device
=
platform_device_register_simple
(
"maceps2"
,
-
1
,
NULL
,
0
);
if
(
IS_ERR
(
maceps2_device
))
return
PTR_ERR
(
maceps2_device
);
port_data
[
0
].
port
=
&
mace
->
perif
.
ps2
.
keyb
;
port_data
[
0
].
irq
=
MACEISA_KEYB_IRQ
;
port_data
[
1
].
port
=
&
mace
->
perif
.
ps2
.
mouse
;
port_data
[
1
].
irq
=
MACEISA_MOUSE_IRQ
;
maceps2_port
[
0
]
=
maceps2_allocate_port
(
0
);
maceps2_port
[
1
]
=
maceps2_allocate_port
(
1
);
if
(
!
maceps2_port
[
0
]
||
!
maceps2_port
[
1
])
{
kfree
(
maceps2_port
[
0
]);
kfree
(
maceps2_port
[
1
]);
platform_device_unregister
(
maceps2_device
);
return
-
ENOMEM
;
}
serio_register_port
(
maceps2_port
[
0
]);
serio_register_port
(
maceps2_port
[
1
]);
return
0
;
}
static
void
__exit
maceps2_exit
(
void
)
{
serio_unregister_port
(
&
maceps2_port0
);
serio_unregister_port
(
&
maceps2_port1
);
serio_unregister_port
(
maceps2_port
[
0
]);
serio_unregister_port
(
maceps2_port
[
1
]);
platform_device_unregister
(
maceps2_device
);
}
module_init
(
maceps2_init
);
...
...
drivers/input/serio/parkbd.c
View file @
73df7566
...
...
@@ -53,9 +53,7 @@ static int parkbd_writing;
static
unsigned
long
parkbd_start
;
static
struct
pardevice
*
parkbd_dev
;
static
char
parkbd_name
[]
=
"PARKBD AT/XT keyboard adapter"
;
static
char
parkbd_phys
[
32
];
static
struct
serio
*
parkbd_port
;
static
int
parkbd_readlines
(
void
)
{
...
...
@@ -86,13 +84,6 @@ static int parkbd_write(struct serio *port, unsigned char c)
return
0
;
}
static
struct
serio
parkbd_port
=
{
.
write
=
parkbd_write
,
.
name
=
parkbd_name
,
.
phys
=
parkbd_phys
,
};
static
void
parkbd_interrupt
(
int
irq
,
void
*
dev_id
,
struct
pt_regs
*
regs
)
{
...
...
@@ -125,7 +116,7 @@ static void parkbd_interrupt(int irq, void *dev_id, struct pt_regs *regs)
parkbd_buffer
|=
(
parkbd_readlines
()
>>
1
)
<<
parkbd_counter
++
;
if
(
parkbd_counter
==
parkbd_mode
+
10
)
serio_interrupt
(
&
parkbd_port
,
(
parkbd_buffer
>>
(
2
-
parkbd_mode
))
&
0xff
,
0
,
regs
);
serio_interrupt
(
parkbd_port
,
(
parkbd_buffer
>>
(
2
-
parkbd_mode
))
&
0xff
,
0
,
regs
);
}
parkbd_last
=
jiffies
;
...
...
@@ -163,16 +154,38 @@ static int parkbd_getport(void)
return
0
;
}
static
struct
serio
*
__init
parkbd_allocate_serio
(
void
)
{
struct
serio
*
serio
;
serio
=
kmalloc
(
sizeof
(
struct
serio
),
GFP_KERNEL
);
if
(
serio
)
{
serio
->
type
=
parkbd_mode
;
serio
->
write
=
parkbd_write
,
strlcpy
(
serio
->
name
,
"PARKBD AT/XT keyboard adapter"
,
sizeof
(
serio
->
name
));
snprintf
(
serio
->
phys
,
sizeof
(
serio
->
phys
),
"%s/serio0"
,
parkbd_dev
->
port
->
name
);
}
return
serio
;
}
int
__init
parkbd_init
(
void
)
{
if
(
parkbd_getport
())
return
-
1
;
parkbd_writelines
(
3
);
parkbd_port
.
type
=
parkbd_mode
;
int
err
;
err
=
parkbd_getport
();
if
(
err
)
return
err
;
sprintf
(
parkbd_phys
,
"%s/serio0"
,
parkbd_dev
->
port
->
name
);
parkbd_port
=
parkbd_allocate_serio
();
if
(
!
parkbd_port
)
{
parport_release
(
parkbd_dev
);
return
-
ENOMEM
;
}
parkbd_writelines
(
3
);
serio_register_port
(
&
parkbd_port
);
serio_register_port
(
parkbd_port
);
printk
(
KERN_INFO
"serio: PARKBD %s adapter on %s
\n
"
,
parkbd_mode
?
"AT"
:
"XT"
,
parkbd_dev
->
port
->
name
);
...
...
@@ -183,7 +196,7 @@ int __init parkbd_init(void)
void
__exit
parkbd_exit
(
void
)
{
parport_release
(
parkbd_dev
);
serio_unregister_port
(
&
parkbd_port
);
serio_unregister_port
(
parkbd_port
);
parport_unregister_device
(
parkbd_dev
);
}
...
...
drivers/input/serio/pcips2.c
View file @
73df7566
...
...
@@ -38,14 +38,14 @@
#define PS2_STAT_TXEMPTY (1<<7)
struct
pcips2_data
{
struct
serio
io
;
struct
serio
*
io
;
unsigned
int
base
;
struct
pci_dev
*
dev
;
};
static
int
pcips2_write
(
struct
serio
*
io
,
unsigned
char
val
)
{
struct
pcips2_data
*
ps2if
=
io
->
driver
;
struct
pcips2_data
*
ps2if
=
io
->
port_data
;
unsigned
int
stat
;
do
{
...
...
@@ -80,7 +80,7 @@ static irqreturn_t pcips2_interrupt(int irq, void *devid, struct pt_regs *regs)
if
(
hweight8
(
scancode
)
&
1
)
flag
^=
SERIO_PARITY
;
serio_interrupt
(
&
ps2if
->
io
,
scancode
,
flag
,
regs
);
serio_interrupt
(
ps2if
->
io
,
scancode
,
flag
,
regs
);
}
while
(
1
);
return
IRQ_RETVAL
(
handled
);
}
...
...
@@ -101,7 +101,7 @@ static void pcips2_flush_input(struct pcips2_data *ps2if)
static
int
pcips2_open
(
struct
serio
*
io
)
{
struct
pcips2_data
*
ps2if
=
io
->
driver
;
struct
pcips2_data
*
ps2if
=
io
->
port_data
;
int
ret
,
val
=
0
;
outb
(
PS2_CTRL_ENABLE
,
ps2if
->
base
);
...
...
@@ -119,7 +119,7 @@ static int pcips2_open(struct serio *io)
static
void
pcips2_close
(
struct
serio
*
io
)
{
struct
pcips2_data
*
ps2if
=
io
->
driver
;
struct
pcips2_data
*
ps2if
=
io
->
port_data
;
outb
(
0
,
ps2if
->
base
);
...
...
@@ -129,46 +129,51 @@ static void pcips2_close(struct serio *io)
static
int
__devinit
pcips2_probe
(
struct
pci_dev
*
dev
,
const
struct
pci_device_id
*
id
)
{
struct
pcips2_data
*
ps2if
;
struct
serio
*
serio
;
int
ret
;
ret
=
pci_enable_device
(
dev
);
if
(
ret
)
return
re
t
;
goto
ou
t
;
if
(
!
request_region
(
pci_resource_start
(
dev
,
0
),
pci_resource_len
(
dev
,
0
),
"pcips2"
))
{
ret
=
-
EBUSY
;
ret
=
pci_request_regions
(
dev
,
"pcips2"
);
if
(
ret
)
goto
disable
;
}
ps2if
=
kmalloc
(
sizeof
(
struct
pcips2_data
),
GFP_KERNEL
);
if
(
!
ps2if
)
{
serio
=
kmalloc
(
sizeof
(
struct
serio
),
GFP_KERNEL
);
if
(
!
ps2if
||
!
serio
)
{
ret
=
-
ENOMEM
;
goto
release
;
}
memset
(
ps2if
,
0
,
sizeof
(
struct
pcips2_data
));
ps2if
->
io
.
type
=
SERIO_8042
;
ps2if
->
io
.
write
=
pcips2_write
;
ps2if
->
io
.
open
=
pcips2_open
;
ps2if
->
io
.
close
=
pcips2_close
;
ps2if
->
io
.
name
=
pci_name
(
dev
);
ps2if
->
io
.
phys
=
dev
->
dev
.
bus_id
;
ps2if
->
io
.
driver
=
ps2if
;
memset
(
serio
,
0
,
sizeof
(
struct
serio
));
serio
->
type
=
SERIO_8042
;
serio
->
write
=
pcips2_write
;
serio
->
open
=
pcips2_open
;
serio
->
close
=
pcips2_close
;
strlcpy
(
serio
->
name
,
pci_name
(
dev
),
sizeof
(
serio
->
name
));
strlcpy
(
serio
->
phys
,
dev
->
dev
.
bus_id
,
sizeof
(
serio
->
phys
));
serio
->
port_data
=
ps2if
;
serio
->
dev
.
parent
=
&
dev
->
dev
;
ps2if
->
io
=
serio
;
ps2if
->
dev
=
dev
;
ps2if
->
base
=
pci_resource_start
(
dev
,
0
);
pci_set_drvdata
(
dev
,
ps2if
);
serio_register_port
(
&
ps2if
->
io
);
serio_register_port
(
ps2if
->
io
);
return
0
;
release:
release_region
(
pci_resource_start
(
dev
,
0
),
pci_resource_len
(
dev
,
0
));
kfree
(
ps2if
);
kfree
(
serio
);
pci_release_regions
(
dev
);
disable:
pci_disable_device
(
dev
);
out:
return
ret
;
}
...
...
@@ -176,11 +181,10 @@ static void __devexit pcips2_remove(struct pci_dev *dev)
{
struct
pcips2_data
*
ps2if
=
pci_get_drvdata
(
dev
);
serio_unregister_port
(
&
ps2if
->
io
);
release_region
(
pci_resource_start
(
dev
,
0
),
pci_resource_len
(
dev
,
0
));
serio_unregister_port
(
ps2if
->
io
);
pci_set_drvdata
(
dev
,
NULL
);
kfree
(
ps2if
);
pci_release_regions
(
dev
);
pci_disable_device
(
dev
);
}
...
...
drivers/input/serio/q40kbd.c
View file @
73df7566
...
...
@@ -35,6 +35,7 @@
#include <linux/init.h>
#include <linux/serio.h>
#include <linux/interrupt.h>
#include <linux/err.h>
#include <asm/bitops.h>
#include <asm/io.h>
...
...
@@ -47,43 +48,106 @@ MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
MODULE_DESCRIPTION
(
"Q40 PS/2 keyboard controller driver"
);
MODULE_LICENSE
(
"GPL"
);
static
struct
serio
q40kbd_port
=
{
.
type
=
SERIO_8042
,
.
name
=
"Q40 kbd port"
,
.
phys
=
"Q40"
,
.
write
=
NULL
,
};
static
irqreturn_t
q40kbd_interrupt
(
int
irq
,
void
*
dev_id
,
struct
pt_regs
*
regs
)
spinlock_t
q40kbd_lock
=
SPIN_LOCK_UNLOCKED
;
static
struct
serio
*
q40kbd_port
;
static
struct
platform_device
*
q40kbd_device
;
static
irqreturn_t
q40kbd_interrupt
(
int
irq
,
void
*
dev_id
,
struct
pt_regs
*
regs
)
{
unsigned
long
flags
;
spin_lock_irqsave
(
&
q40kbd_lock
,
flags
);
if
(
Q40_IRQ_KEYB_MASK
&
master_inb
(
INTERRUPT_REG
))
serio_interrupt
(
&
q40kbd_port
,
master_inb
(
KEYCODE_REG
),
0
,
regs
);
serio_interrupt
(
q40kbd_port
,
master_inb
(
KEYCODE_REG
),
0
,
regs
);
master_outb
(
-
1
,
KEYBOARD_UNLOCK_REG
);
spin_unlock_irqrestore
(
&
q40kbd_lock
,
flags
);
return
IRQ_HANDLED
;
}
static
int
__init
q40kbd_init
(
void
)
/*
* q40kbd_flush() flushes all data that may be in the keyboard buffers
*/
static
void
q40kbd_flush
(
void
)
{
int
maxread
=
100
;
unsigned
long
flags
;
spin_lock_irqsave
(
&
q40kbd_lock
,
flags
);
while
(
maxread
--
&&
(
Q40_IRQ_KEYB_MASK
&
master_inb
(
INTERRUPT_REG
)))
master_inb
(
KEYCODE_REG
);
spin_unlock_irqrestore
(
&
q40kbd_lock
,
flags
);
}
/*
* q40kbd_open() is called when a port is open by the higher layer.
* It allocates the interrupt and enables in in the chip.
*/
static
int
q40kbd_open
(
struct
serio
*
port
)
{
int
maxread
=
100
;
q40kbd_flush
()
;
if
(
request_irq
(
Q40_IRQ_KEYBOARD
,
q40kbd_interrupt
,
0
,
"q40kbd"
,
NULL
))
{
printk
(
KERN_ERR
"q40kbd.c: Can't get irq %d.
\n
"
,
Q40_IRQ_KEYBOARD
);
return
-
1
;
}
/* off we go */
master_outb
(
-
1
,
KEYBOARD_UNLOCK_REG
);
master_outb
(
1
,
KEY_IRQ_ENABLE_REG
);
return
0
;
}
static
void
q40kbd_close
(
struct
serio
*
port
)
{
master_outb
(
0
,
KEY_IRQ_ENABLE_REG
);
master_outb
(
-
1
,
KEYBOARD_UNLOCK_REG
);
free_irq
(
Q40_IRQ_KEYBOARD
,
NULL
);
q40kbd_flush
();
}
static
struct
serio
*
__init
q40kbd_allocate_port
(
void
)
{
struct
serio
*
serio
;
serio
=
kmalloc
(
sizeof
(
struct
serio
),
GFP_KERNEL
);
if
(
serio
)
{
memset
(
serio
,
0
,
sizeof
(
struct
serio
));
serio
->
type
=
SERIO_8042
;
serio
->
open
=
q40kbd_open
;
serio
->
close
=
q40kbd_close
;
serio
->
dev
.
parent
=
&
q40kbd_device
->
dev
;
strlcpy
(
serio
->
name
,
"Q40 Kbd Port"
,
sizeof
(
serio
->
name
));
strlcpy
(
serio
->
phys
,
"Q40"
,
sizeof
(
serio
->
phys
));
}
return
serio
;
}
static
int
__init
q40kbd_init
(
void
)
{
if
(
!
MACH_IS_Q40
)
return
-
EIO
;
/* allocate the IRQ */
request_irq
(
Q40_IRQ_KEYBOARD
,
q40kbd_interrupt
,
0
,
"q40kbd"
,
NULL
);
/* flush any pending input */
while
(
maxread
--
&&
(
Q40_IRQ_KEYB_MASK
&
master_inb
(
INTERRUPT_REG
)))
master_inb
(
KEYCODE_REG
);
q40kbd_device
=
platform_device_register_simple
(
"q40kbd"
,
-
1
,
NULL
,
0
);
if
(
IS_ERR
(
q40kbd_device
))
return
PTR_ERR
(
q40kbd_device
);
/* off we go */
master_outb
(
-
1
,
KEYBOARD_UNLOCK_REG
);
master_outb
(
1
,
KEY_IRQ_ENABLE_REG
);
if
(
!
(
q40kbd_port
=
q40kbd_allocate_port
()))
{
platform_device_unregister
(
q40kbd_device
);
return
-
ENOMEM
;
}
serio_register_port
(
&
q40kbd_port
);
serio_register_port
(
q40kbd_port
);
printk
(
KERN_INFO
"serio: Q40 kbd registered
\n
"
);
return
0
;
...
...
@@ -91,11 +155,8 @@ static int __init q40kbd_init(void)
static
void
__exit
q40kbd_exit
(
void
)
{
master_outb
(
0
,
KEY_IRQ_ENABLE_REG
);
master_outb
(
-
1
,
KEYBOARD_UNLOCK_REG
);
serio_unregister_port
(
&
q40kbd_port
);
free_irq
(
Q40_IRQ_KEYBOARD
,
NULL
);
serio_unregister_port
(
q40kbd_port
);
platform_device_unregister
(
q40kbd_device
);
}
module_init
(
q40kbd_init
);
...
...
drivers/input/serio/rpckbd.c
View file @
73df7566
...
...
@@ -33,6 +33,7 @@
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/serio.h>
#include <linux/err.h>
#include <asm/irq.h>
#include <asm/hardware.h>
...
...
@@ -44,6 +45,9 @@ MODULE_AUTHOR("Vojtech Pavlik, Russell King");
MODULE_DESCRIPTION
(
"Acorn RiscPC PS/2 keyboard controller driver"
);
MODULE_LICENSE
(
"GPL"
);
static
struct
serio
*
rpckbd_port
;
static
struct
platform_device
*
rpckbd_device
;
static
int
rpckbd_write
(
struct
serio
*
port
,
unsigned
char
val
)
{
while
(
!
(
iomd_readb
(
IOMD_KCTRL
)
&
(
1
<<
7
)))
...
...
@@ -101,25 +105,49 @@ static void rpckbd_close(struct serio *port)
free_irq
(
IRQ_KEYBOARDTX
,
port
);
}
static
struct
serio
rpckbd_port
=
/*
* Allocate and initialize serio structure for subsequent registration
* with serio core.
*/
static
struct
serio
*
__init
rpckbd_allocate_port
(
void
)
{
.
type
=
SERIO_8042
,
.
open
=
rpckbd_open
,
.
close
=
rpckbd_close
,
.
write
=
rpckbd_write
,
.
name
=
"RiscPC PS/2 kbd port"
,
.
phys
=
"rpckbd/serio0"
,
};
struct
serio
*
serio
;
serio
=
kmalloc
(
sizeof
(
struct
serio
),
GFP_KERNEL
);
if
(
serio
)
{
memset
(
serio
,
0
,
sizeof
(
struct
serio
));
serio
->
type
=
SERIO_8042
;
serio
->
write
=
rpckbd_write
;
serio
->
open
=
rpckbd_open
;
serio
->
close
=
rpckbd_close
;
serio
->
dev
.
parent
=
&
rpckbd_device
->
dev
;
strlcpy
(
serio
->
name
,
"RiscPC PS/2 kbd port"
,
sizeof
(
serio
->
name
));
strlcpy
(
serio
->
phys
,
"rpckbd/serio0"
,
sizeof
(
serio
->
phys
));
}
return
serio
;
}
static
int
__init
rpckbd_init
(
void
)
{
serio_register_port
(
&
rpckbd_port
);
rpckbd_device
=
platform_device_register_simple
(
"rpckbd"
,
-
1
,
NULL
,
0
);
if
(
IS_ERR
(
rpckbd_device
))
return
PTR_ERR
(
rpckbd_device
);
if
(
!
(
rpckbd_port
=
rpckbd_allocate_port
()))
{
platform_device_unregister
(
rpckbd_device
);
return
-
ENOMEM
;
}
serio_register_port
(
rpckbd_port
);
return
0
;
}
static
void
__exit
rpckbd_exit
(
void
)
{
serio_unregister_port
(
&
rpckbd_port
);
serio_unregister_port
(
rpckbd_port
);
platform_device_unregister
(
rpckbd_device
);
}
module_init
(
rpckbd_init
);
...
...
drivers/input/serio/sa1111ps2.c
View file @
73df7566
...
...
@@ -26,7 +26,7 @@
#include <asm/hardware/sa1111.h>
struct
ps2if
{
struct
serio
io
;
struct
serio
*
io
;
struct
sa1111_dev
*
dev
;
unsigned
long
base
;
unsigned
int
open
;
...
...
@@ -59,7 +59,7 @@ static irqreturn_t ps2_rxint(int irq, void *dev_id, struct pt_regs *regs)
if
(
hweight8
(
scancode
)
&
1
)
flag
^=
SERIO_PARITY
;
serio_interrupt
(
&
ps2if
->
io
,
scancode
,
flag
,
regs
);
serio_interrupt
(
ps2if
->
io
,
scancode
,
flag
,
regs
);
status
=
sa1111_readl
(
ps2if
->
base
+
SA1111_PS2STAT
);
}
...
...
@@ -95,7 +95,7 @@ static irqreturn_t ps2_txint(int irq, void *dev_id, struct pt_regs *regs)
*/
static
int
ps2_write
(
struct
serio
*
io
,
unsigned
char
val
)
{
struct
ps2if
*
ps2if
=
io
->
driver
;
struct
ps2if
*
ps2if
=
io
->
port_data
;
unsigned
long
flags
;
unsigned
int
head
;
...
...
@@ -122,7 +122,7 @@ static int ps2_write(struct serio *io, unsigned char val)
static
int
ps2_open
(
struct
serio
*
io
)
{
struct
ps2if
*
ps2if
=
io
->
driver
;
struct
ps2if
*
ps2if
=
io
->
port_data
;
int
ret
;
sa1111_enable_device
(
ps2if
->
dev
);
...
...
@@ -154,7 +154,7 @@ static int ps2_open(struct serio *io)
static
void
ps2_close
(
struct
serio
*
io
)
{
struct
ps2if
*
ps2if
=
io
->
driver
;
struct
ps2if
*
ps2if
=
io
->
port_data
;
sa1111_writel
(
0
,
ps2if
->
base
+
SA1111_PS2CR
);
...
...
@@ -232,22 +232,28 @@ static int __init ps2_test(struct ps2if *ps2if)
static
int
ps2_probe
(
struct
sa1111_dev
*
dev
)
{
struct
ps2if
*
ps2if
;
struct
serio
*
serio
;
int
ret
;
ps2if
=
kmalloc
(
sizeof
(
struct
ps2if
),
GFP_KERNEL
);
if
(
!
ps2if
)
{
return
-
ENOMEM
;
serio
=
kmalloc
(
sizeof
(
struct
serio
),
GFP_KERNEL
);
if
(
!
ps2if
||
!
serio
)
{
ret
=
-
ENOMEM
;
goto
free
;
}
memset
(
ps2if
,
0
,
sizeof
(
struct
ps2if
));
ps2if
->
io
.
type
=
SERIO_8042
;
ps2if
->
io
.
write
=
ps2_write
;
ps2if
->
io
.
open
=
ps2_open
;
ps2if
->
io
.
close
=
ps2_close
;
ps2if
->
io
.
name
=
dev
->
dev
.
bus_id
;
ps2if
->
io
.
phys
=
dev
->
dev
.
bus_id
;
ps2if
->
io
.
driver
=
ps2if
;
memset
(
serio
,
0
,
sizeof
(
struct
serio
));
serio
->
type
=
SERIO_8042
;
serio
->
write
=
ps2_write
;
serio
->
open
=
ps2_open
;
serio
->
close
=
ps2_close
;
strlcpy
(
serio
->
name
,
dev
->
dev
.
bus_id
,
sizeof
(
serio
->
name
));
strlcpy
(
serio
->
phys
,
dev
->
dev
.
bus_id
,
sizeof
(
serio
->
phys
));
serio
->
port_data
=
ps2if
;
serio
->
dev
.
parent
=
&
dev
->
dev
;
ps2if
->
io
=
serio
;
ps2if
->
dev
=
dev
;
sa1111_set_drvdata
(
dev
,
ps2if
);
...
...
@@ -292,7 +298,7 @@ static int ps2_probe(struct sa1111_dev *dev)
ps2_clear_input
(
ps2if
);
sa1111_disable_device
(
ps2if
->
dev
);
serio_register_port
(
&
ps2if
->
io
);
serio_register_port
(
ps2if
->
io
);
return
0
;
out:
...
...
@@ -302,6 +308,7 @@ static int ps2_probe(struct sa1111_dev *dev)
free:
sa1111_set_drvdata
(
dev
,
NULL
);
kfree
(
ps2if
);
kfree
(
serio
);
return
ret
;
}
...
...
@@ -312,7 +319,7 @@ static int ps2_remove(struct sa1111_dev *dev)
{
struct
ps2if
*
ps2if
=
sa1111_get_drvdata
(
dev
);
serio_unregister_port
(
&
ps2if
->
io
);
serio_unregister_port
(
ps2if
->
io
);
release_mem_region
(
dev
->
res
.
start
,
dev
->
res
.
end
-
dev
->
res
.
start
+
1
);
sa1111_set_drvdata
(
dev
,
NULL
);
...
...
drivers/input/serio/serio.c
View file @
73df7566
/*
* $Id: serio.c,v 1.15 2002/01/22 21:12:03 vojtech Exp $
*
* Copyright (c) 1999-2001 Vojtech Pavlik
*/
/*
* The Serio abstraction module
*
* Copyright (c) 1999-2004 Vojtech Pavlik
* Copyright (c) 2004 Dmitry Torokhov
* Copyright (c) 2003 Daniele Bellucci
*/
/*
...
...
@@ -26,10 +24,6 @@
* Should you need to contact me, the author, you can do so either by
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
*
* Changes:
* 20 Jul. 2003 Daniele Bellucci <bellucda@tiscali.it>
* Minor cleanups.
*/
#include <linux/stddef.h>
...
...
@@ -50,100 +44,178 @@ MODULE_LICENSE("GPL");
EXPORT_SYMBOL
(
serio_interrupt
);
EXPORT_SYMBOL
(
serio_register_port
);
EXPORT_SYMBOL
(
serio_register_port_delayed
);
EXPORT_SYMBOL
(
__serio_register_port
);
EXPORT_SYMBOL
(
serio_unregister_port
);
EXPORT_SYMBOL
(
serio_unregister_port_delayed
);
EXPORT_SYMBOL
(
__serio_unregister_port
);
EXPORT_SYMBOL
(
serio_register_device
);
EXPORT_SYMBOL
(
serio_unregister_device
);
EXPORT_SYMBOL
(
serio_register_driver
);
EXPORT_SYMBOL
(
serio_unregister_driver
);
EXPORT_SYMBOL
(
serio_open
);
EXPORT_SYMBOL
(
serio_close
);
EXPORT_SYMBOL
(
serio_rescan
);
EXPORT_SYMBOL
(
serio_reconnect
);
static
DECLARE_MUTEX
(
serio_sem
);
/* protects serio_list and serio_diriver_list */
static
LIST_HEAD
(
serio_list
);
static
LIST_HEAD
(
serio_driver_list
);
static
unsigned
int
serio_no
;
struct
bus_type
serio_bus
=
{
.
name
=
"serio"
,
};
static
void
serio_find_driver
(
struct
serio
*
serio
);
static
void
serio_create_port
(
struct
serio
*
serio
);
static
void
serio_destroy_port
(
struct
serio
*
serio
);
static
void
serio_connect_port
(
struct
serio
*
serio
,
struct
serio_driver
*
drv
);
static
void
serio_reconnect_port
(
struct
serio
*
serio
);
static
void
serio_disconnect_port
(
struct
serio
*
serio
);
static
int
serio_bind_driver
(
struct
serio
*
serio
,
struct
serio_driver
*
drv
)
{
get_driver
(
&
drv
->
driver
);
drv
->
connect
(
serio
,
drv
);
if
(
serio
->
drv
)
{
down_write
(
&
serio_bus
.
subsys
.
rwsem
);
serio
->
dev
.
driver
=
&
drv
->
driver
;
device_bind_driver
(
&
serio
->
dev
);
up_write
(
&
serio_bus
.
subsys
.
rwsem
);
return
1
;
}
put_driver
(
&
drv
->
driver
);
return
0
;
}
/* serio_find_driver() must be called with serio_sem down. */
static
void
serio_find_driver
(
struct
serio
*
serio
)
{
struct
serio_driver
*
drv
;
list_for_each_entry
(
drv
,
&
serio_driver_list
,
node
)
if
(
!
drv
->
manual_bind
)
if
(
serio_bind_driver
(
serio
,
drv
))
break
;
}
/*
* Serio event processing.
*/
struct
serio_event
{
int
type
;
struct
serio
*
serio
;
struct
list_head
node
;
};
static
DECLARE_MUTEX
(
serio_sem
);
static
LIST_HEAD
(
serio_list
);
static
LIST_HEAD
(
serio_dev_list
);
enum
serio_event_type
{
SERIO_RESCAN
,
SERIO_RECONNECT
,
SERIO_REGISTER_PORT
,
SERIO_UNREGISTER_PORT
,
};
static
spinlock_t
serio_event_lock
=
SPIN_LOCK_UNLOCKED
;
/* protects serio_event_list */
static
LIST_HEAD
(
serio_event_list
);
static
DECLARE_WAIT_QUEUE_HEAD
(
serio_wait
);
static
DECLARE_COMPLETION
(
serio_exited
);
static
int
serio_pid
;
static
void
serio_
find_dev
(
struct
serio
*
serio
)
static
void
serio_
queue_event
(
struct
serio
*
serio
,
int
event_type
)
{
struct
serio_dev
*
dev
;
unsigned
long
flags
;
struct
serio_event
*
event
;
list_for_each_entry
(
dev
,
&
serio_dev_list
,
node
)
{
if
(
serio
->
dev
)
break
;
if
(
dev
->
connect
)
dev
->
connect
(
serio
,
dev
);
}
}
spin_lock_irqsave
(
&
serio_event_lock
,
flags
);
#define SERIO_RESCAN 1
#define SERIO_RECONNECT 2
#define SERIO_REGISTER_PORT 3
#define SERIO_UNREGISTER_PORT 4
if
((
event
=
kmalloc
(
sizeof
(
struct
serio_event
),
GFP_ATOMIC
)))
{
event
->
type
=
event_type
;
event
->
serio
=
serio
;
static
DECLARE_WAIT_QUEUE_HEAD
(
serio_wait
);
static
DECLARE_COMPLETION
(
serio_exited
);
list_add_tail
(
&
event
->
node
,
&
serio_event_list
);
wake_up
(
&
serio_wait
);
}
spin_unlock_irqrestore
(
&
serio_event_lock
,
flags
);
}
static
void
serio_invalidate_pending_events
(
struct
serio
*
serio
)
static
struct
serio_event
*
serio_get_event
(
void
)
{
struct
serio_event
*
event
;
struct
list_head
*
node
;
unsigned
long
flags
;
spin_lock_irqsave
(
&
serio_event_lock
,
flags
);
if
(
list_empty
(
&
serio_event_list
))
{
spin_unlock_irqrestore
(
&
serio_event_lock
,
flags
);
return
NULL
;
}
node
=
serio_event_list
.
next
;
event
=
container_of
(
node
,
struct
serio_event
,
node
);
list_del_init
(
node
);
spin_unlock_irqrestore
(
&
serio_event_lock
,
flags
);
list_for_each_entry
(
event
,
&
serio_event_list
,
node
)
if
(
event
->
serio
==
serio
)
event
->
serio
=
NULL
;
return
event
;
}
void
serio_handle_events
(
void
)
static
void
serio_handle_events
(
void
)
{
struct
list_head
*
node
,
*
next
;
struct
serio_event
*
event
;
list_for_each_safe
(
node
,
next
,
&
serio_event_list
)
{
event
=
container_of
(
node
,
struct
serio_event
,
node
);
while
((
event
=
serio_get_event
()))
{
down
(
&
serio_sem
);
if
(
event
->
serio
==
NULL
)
goto
event_done
;
switch
(
event
->
type
)
{
case
SERIO_REGISTER_PORT
:
__serio_register_port
(
event
->
serio
);
serio_create_port
(
event
->
serio
);
serio_connect_port
(
event
->
serio
,
NULL
);
break
;
case
SERIO_UNREGISTER_PORT
:
__serio_unregister_port
(
event
->
serio
);
serio_disconnect_port
(
event
->
serio
);
serio_destroy_port
(
event
->
serio
);
break
;
case
SERIO_RECONNECT
:
if
(
event
->
serio
->
dev
&&
event
->
serio
->
dev
->
reconnect
)
if
(
event
->
serio
->
dev
->
reconnect
(
event
->
serio
)
==
0
)
break
;
/* reconnect failed - fall through to rescan */
serio_reconnect_port
(
event
->
serio
);
break
;
case
SERIO_RESCAN
:
if
(
event
->
serio
->
dev
&&
event
->
serio
->
dev
->
disconnect
)
event
->
serio
->
dev
->
disconnect
(
event
->
serio
);
serio_find_dev
(
event
->
serio
);
serio_disconnect_port
(
event
->
serio
);
serio_connect_port
(
event
->
serio
,
NULL
);
break
;
default:
break
;
}
event_done:
up
(
&
serio_sem
);
list_del_init
(
node
);
kfree
(
event
);
}
}
static
void
serio_remove_pending_events
(
struct
serio
*
serio
)
{
struct
list_head
*
node
,
*
next
;
struct
serio_event
*
event
;
unsigned
long
flags
;
spin_lock_irqsave
(
&
serio_event_lock
,
flags
);
list_for_each_safe
(
node
,
next
,
&
serio_event_list
)
{
event
=
container_of
(
node
,
struct
serio_event
,
node
);
if
(
event
->
serio
==
serio
)
{
list_del_init
(
node
);
kfree
(
event
);
}
}
spin_unlock_irqrestore
(
&
serio_event_lock
,
flags
);
}
static
int
serio_thread
(
void
*
nothing
)
{
lock_kernel
();
...
...
@@ -163,52 +235,239 @@ static int serio_thread(void *nothing)
complete_and_exit
(
&
serio_exited
,
0
);
}
static
void
serio_queue_event
(
struct
serio
*
serio
,
int
event_type
)
/*
* Serio port operations
*/
static
ssize_t
serio_show_description
(
struct
device
*
dev
,
char
*
buf
)
{
struct
serio_event
*
event
;
struct
serio
*
serio
=
to_serio_port
(
dev
);
return
sprintf
(
buf
,
"%s
\n
"
,
serio
->
name
);
}
if
((
event
=
kmalloc
(
sizeof
(
struct
serio_event
),
GFP_ATOMIC
)))
{
event
->
type
=
event_type
;
event
->
serio
=
serio
;
static
ssize_t
serio_show_driver
(
struct
device
*
dev
,
char
*
buf
)
{
return
sprintf
(
buf
,
"%s
\n
"
,
dev
->
driver
?
dev
->
driver
->
name
:
"(none)"
);
}
list_add_tail
(
&
event
->
node
,
&
serio_event_list
);
wake_up
(
&
serio_wait
);
static
ssize_t
serio_rebind_driver
(
struct
device
*
dev
,
const
char
*
buf
,
size_t
count
)
{
struct
serio
*
serio
=
to_serio_port
(
dev
);
struct
device_driver
*
drv
;
int
retval
;
retval
=
down_interruptible
(
&
serio_sem
);
if
(
retval
)
return
retval
;
retval
=
count
;
if
(
!
strncmp
(
buf
,
"none"
,
count
))
{
serio_disconnect_port
(
serio
);
}
else
if
(
!
strncmp
(
buf
,
"reconnect"
,
count
))
{
serio_reconnect_port
(
serio
);
}
else
if
(
!
strncmp
(
buf
,
"rescan"
,
count
))
{
serio_disconnect_port
(
serio
);
serio_connect_port
(
serio
,
NULL
);
}
else
if
((
drv
=
driver_find
(
buf
,
&
serio_bus
))
!=
NULL
)
{
serio_disconnect_port
(
serio
);
serio_connect_port
(
serio
,
to_serio_driver
(
drv
));
put_driver
(
drv
);
}
else
{
retval
=
-
EINVAL
;
}
up
(
&
serio_sem
);
return
retval
;
}
void
serio_rescan
(
struct
serio
*
serio
)
static
ssize_t
serio_show_bind_mode
(
struct
device
*
dev
,
char
*
buf
)
{
serio_queue_event
(
serio
,
SERIO_RESCAN
);
struct
serio
*
serio
=
to_serio_port
(
dev
);
return
sprintf
(
buf
,
"%s
\n
"
,
serio
->
manual_bind
?
"manual"
:
"auto"
);
}
void
serio_reconnect
(
struct
serio
*
serio
)
static
ssize_t
serio_set_bind_mode
(
struct
device
*
dev
,
const
char
*
buf
,
size_t
count
)
{
serio_queue_event
(
serio
,
SERIO_RECONNECT
);
struct
serio
*
serio
=
to_serio_port
(
dev
);
int
retval
;
retval
=
count
;
if
(
!
strncmp
(
buf
,
"manual"
,
count
))
{
serio
->
manual_bind
=
1
;
}
else
if
(
!
strncmp
(
buf
,
"auto"
,
count
))
{
serio
->
manual_bind
=
0
;
}
else
{
retval
=
-
EINVAL
;
}
return
retval
;
}
irqreturn_t
serio_interrupt
(
struct
serio
*
serio
,
unsigned
char
data
,
unsigned
int
flags
,
struct
pt_regs
*
regs
)
static
struct
device_attribute
serio_device_attrs
[]
=
{
__ATTR
(
description
,
S_IRUGO
,
serio_show_description
,
NULL
),
__ATTR
(
driver
,
S_IWUSR
|
S_IRUGO
,
serio_show_driver
,
serio_rebind_driver
),
__ATTR
(
bind_mode
,
S_IWUSR
|
S_IRUGO
,
serio_show_bind_mode
,
serio_set_bind_mode
),
__ATTR_NULL
};
static
void
serio_release_port
(
struct
device
*
dev
)
{
irqreturn_t
ret
=
IRQ_NONE
;
struct
serio
*
serio
=
to_serio_port
(
dev
)
;
if
(
serio
->
dev
&&
serio
->
dev
->
interrupt
)
{
ret
=
serio
->
dev
->
interrupt
(
serio
,
data
,
flags
,
regs
);
}
else
{
if
(
!
flags
)
{
if
((
serio
->
type
==
SERIO_8042
||
serio
->
type
==
SERIO_8042_XL
)
&&
(
data
!=
0xaa
))
return
ret
;
serio_rescan
(
serio
);
ret
=
IRQ_HANDLED
;
kfree
(
serio
);
module_put
(
THIS_MODULE
);
}
static
void
serio_create_port
(
struct
serio
*
serio
)
{
try_module_get
(
THIS_MODULE
);
spin_lock_init
(
&
serio
->
lock
);
list_add_tail
(
&
serio
->
node
,
&
serio_list
);
snprintf
(
serio
->
dev
.
bus_id
,
sizeof
(
serio
->
dev
.
bus_id
),
"serio%d"
,
serio_no
++
);
serio
->
dev
.
bus
=
&
serio_bus
;
serio
->
dev
.
release
=
serio_release_port
;
if
(
serio
->
parent
)
serio
->
dev
.
parent
=
&
serio
->
parent
->
dev
;
device_register
(
&
serio
->
dev
);
}
/*
* serio_destroy_port() completes deregistration process and removes
* port from the system
*/
static
void
serio_destroy_port
(
struct
serio
*
serio
)
{
struct
serio_driver
*
drv
=
serio
->
drv
;
unsigned
long
flags
;
serio_remove_pending_events
(
serio
);
list_del_init
(
&
serio
->
node
);
if
(
drv
)
{
drv
->
disconnect
(
serio
);
down_write
(
&
serio_bus
.
subsys
.
rwsem
);
device_release_driver
(
&
serio
->
dev
);
up_write
(
&
serio_bus
.
subsys
.
rwsem
);
put_driver
(
&
drv
->
driver
);
}
if
(
serio
->
parent
)
{
spin_lock_irqsave
(
&
serio
->
parent
->
lock
,
flags
);
serio
->
parent
->
child
=
NULL
;
spin_unlock_irqrestore
(
&
serio
->
parent
->
lock
,
flags
);
}
device_unregister
(
&
serio
->
dev
);
}
/*
* serio_connect_port() tries to bind the port and possible all its
* children to appropriate drivers. If driver passed in the function will not
* try otehr drivers when binding parent port.
*/
static
void
serio_connect_port
(
struct
serio
*
serio
,
struct
serio_driver
*
drv
)
{
WARN_ON
(
serio
->
drv
);
WARN_ON
(
serio
->
child
);
if
(
drv
)
serio_bind_driver
(
serio
,
drv
);
else
if
(
!
serio
->
manual_bind
)
serio_find_driver
(
serio
);
/* Ok, now bind children, if any */
while
(
serio
->
child
)
{
serio
=
serio
->
child
;
WARN_ON
(
serio
->
drv
);
WARN_ON
(
serio
->
child
);
serio_create_port
(
serio
);
if
(
!
serio
->
manual_bind
)
{
/*
* With children we just _prefer_ passed in driver,
* but we will try other options in case preferred
* is not the one
*/
if
(
!
drv
||
!
serio_bind_driver
(
serio
,
drv
))
serio_find_driver
(
serio
);
}
}
return
ret
;
}
/*
*
*/
static
void
serio_reconnect_port
(
struct
serio
*
serio
)
{
do
{
if
(
!
serio
->
drv
||
!
serio
->
drv
->
reconnect
||
serio
->
drv
->
reconnect
(
serio
))
{
serio_disconnect_port
(
serio
);
serio_connect_port
(
serio
,
NULL
);
/* Ok, old children are now gone, we are done */
break
;
}
serio
=
serio
->
child
;
}
while
(
serio
);
}
/*
* serio_disconnect_port() unbinds a port from its driver. As a side effect
* all child ports are unbound and destroyed.
*/
static
void
serio_disconnect_port
(
struct
serio
*
serio
)
{
struct
serio_driver
*
drv
=
serio
->
drv
;
struct
serio
*
s
;
if
(
serio
->
child
)
{
/*
* Children ports should be disconnected and destroyed
* first, staring with the leaf one, since we don't want
* to do recursion
*/
do
{
s
=
serio
->
child
;
}
while
(
s
->
child
);
while
(
s
!=
serio
)
{
s
=
s
->
parent
;
serio_destroy_port
(
s
->
child
);
}
}
/*
* Ok, no children left, now disconnect this port
*/
if
(
drv
)
{
drv
->
disconnect
(
serio
);
down_write
(
&
serio_bus
.
subsys
.
rwsem
);
device_release_driver
(
&
serio
->
dev
);
up_write
(
&
serio_bus
.
subsys
.
rwsem
);
put_driver
(
&
drv
->
driver
);
}
}
void
serio_rescan
(
struct
serio
*
serio
)
{
serio_queue_event
(
serio
,
SERIO_RESCAN
);
}
void
serio_reconnect
(
struct
serio
*
serio
)
{
serio_queue_event
(
serio
,
SERIO_RECONNECT
);
}
void
serio_register_port
(
struct
serio
*
serio
)
{
down
(
&
serio_sem
);
__serio_register_port
(
serio
);
serio_create_port
(
serio
);
serio_connect_port
(
serio
,
NULL
);
up
(
&
serio_sem
);
}
...
...
@@ -222,21 +481,11 @@ void serio_register_port_delayed(struct serio *serio)
serio_queue_event
(
serio
,
SERIO_REGISTER_PORT
);
}
/*
* Should only be called directly if serio_sem has already been taken,
* for example when unregistering a serio from other input device's
* connect() function.
*/
void
__serio_register_port
(
struct
serio
*
serio
)
{
list_add_tail
(
&
serio
->
node
,
&
serio_list
);
serio_find_dev
(
serio
);
}
void
serio_unregister_port
(
struct
serio
*
serio
)
{
down
(
&
serio_sem
);
__serio_unregister_port
(
serio
);
serio_disconnect_port
(
serio
);
serio_destroy_port
(
serio
);
up
(
&
serio_sem
);
}
...
...
@@ -250,82 +499,171 @@ void serio_unregister_port_delayed(struct serio *serio)
serio_queue_event
(
serio
,
SERIO_UNREGISTER_PORT
);
}
/*
* Should only be called directly if serio_sem has already been taken,
* for example when unregistering a serio from other input device's
* disconnect() function.
* Serio driver operations
*/
void
__serio_unregister_port
(
struct
serio
*
serio
)
static
ssize_t
serio_driver_show_description
(
struct
device_driver
*
drv
,
char
*
buf
)
{
serio_invalidate_pending_events
(
serio
);
list_del_init
(
&
serio
->
node
);
if
(
serio
->
dev
&&
serio
->
dev
->
disconnect
)
serio
->
dev
->
disconnect
(
serio
);
struct
serio_driver
*
driver
=
to_serio_driver
(
drv
);
return
sprintf
(
buf
,
"%s
\n
"
,
driver
->
description
?
driver
->
description
:
"(none)"
);
}
static
ssize_t
serio_driver_show_bind_mode
(
struct
device_driver
*
drv
,
char
*
buf
)
{
struct
serio_driver
*
serio_drv
=
to_serio_driver
(
drv
);
return
sprintf
(
buf
,
"%s
\n
"
,
serio_drv
->
manual_bind
?
"manual"
:
"auto"
);
}
void
serio_register_device
(
struct
serio_dev
*
dev
)
static
ssize_t
serio_driver_set_bind_mode
(
struct
device_driver
*
drv
,
const
char
*
buf
,
size_t
count
)
{
struct
serio_driver
*
serio_drv
=
to_serio_driver
(
drv
);
int
retval
;
retval
=
count
;
if
(
!
strncmp
(
buf
,
"manual"
,
count
))
{
serio_drv
->
manual_bind
=
1
;
}
else
if
(
!
strncmp
(
buf
,
"auto"
,
count
))
{
serio_drv
->
manual_bind
=
0
;
}
else
{
retval
=
-
EINVAL
;
}
return
retval
;
}
static
struct
driver_attribute
serio_driver_attrs
[]
=
{
__ATTR
(
description
,
S_IRUGO
,
serio_driver_show_description
,
NULL
),
__ATTR
(
bind_mode
,
S_IWUSR
|
S_IRUGO
,
serio_driver_show_bind_mode
,
serio_driver_set_bind_mode
),
__ATTR_NULL
};
void
serio_register_driver
(
struct
serio_driver
*
drv
)
{
struct
serio
*
serio
;
down
(
&
serio_sem
);
list_add_tail
(
&
dev
->
node
,
&
serio_dev_list
);
list_for_each_entry
(
serio
,
&
serio_list
,
node
)
if
(
!
serio
->
dev
&&
dev
->
connect
)
dev
->
connect
(
serio
,
dev
);
list_add_tail
(
&
drv
->
node
,
&
serio_driver_list
);
drv
->
driver
.
bus
=
&
serio_bus
;
driver_register
(
&
drv
->
driver
);
if
(
drv
->
manual_bind
)
goto
out
;
start_over:
list_for_each_entry
(
serio
,
&
serio_list
,
node
)
{
if
(
!
serio
->
drv
)
{
serio_connect_port
(
serio
,
drv
);
/*
* if new child appeared then the list is changed,
* we need to start over
*/
if
(
serio
->
child
)
goto
start_over
;
}
}
out:
up
(
&
serio_sem
);
}
void
serio_unregister_d
evice
(
struct
serio_dev
*
de
v
)
void
serio_unregister_d
river
(
struct
serio_driver
*
dr
v
)
{
struct
serio
*
serio
;
down
(
&
serio_sem
);
list_del_init
(
&
dev
->
node
);
list_del_init
(
&
drv
->
node
);
start_over:
list_for_each_entry
(
serio
,
&
serio_list
,
node
)
{
if
(
serio
->
dev
==
dev
&&
dev
->
disconnect
)
dev
->
disconnect
(
serio
);
serio_find_dev
(
serio
);
if
(
serio
->
drv
==
drv
)
{
serio_disconnect_port
(
serio
);
serio_connect_port
(
serio
,
NULL
);
/* we could've deleted some ports, restart */
goto
start_over
;
}
}
driver_unregister
(
&
drv
->
driver
);
up
(
&
serio_sem
);
}
/* called from serio_d
ev
->connect/disconnect methods under serio_sem */
int
serio_open
(
struct
serio
*
serio
,
struct
serio_d
ev
*
de
v
)
/* called from serio_d
river
->connect/disconnect methods under serio_sem */
int
serio_open
(
struct
serio
*
serio
,
struct
serio_d
river
*
dr
v
)
{
serio
->
dev
=
dev
;
serio_pause_rx
(
serio
);
serio
->
drv
=
drv
;
serio_continue_rx
(
serio
);
if
(
serio
->
open
&&
serio
->
open
(
serio
))
{
serio
->
dev
=
NULL
;
serio_pause_rx
(
serio
);
serio
->
drv
=
NULL
;
serio_continue_rx
(
serio
);
return
-
1
;
}
return
0
;
}
/* called from serio_d
ev
->connect/disconnect methods under serio_sem */
/* called from serio_d
river
->connect/disconnect methods under serio_sem */
void
serio_close
(
struct
serio
*
serio
)
{
if
(
serio
->
close
)
serio
->
close
(
serio
);
serio
->
dev
=
NULL
;
serio_pause_rx
(
serio
);
serio
->
drv
=
NULL
;
serio_continue_rx
(
serio
);
}
static
int
__init
serio_init
(
void
)
irqreturn_t
serio_interrupt
(
struct
serio
*
serio
,
unsigned
char
data
,
unsigned
int
dfl
,
struct
pt_regs
*
regs
)
{
int
pid
;
unsigned
long
flags
;
irqreturn_t
ret
=
IRQ_NONE
;
spin_lock_irqsave
(
&
serio
->
lock
,
flags
);
if
(
likely
(
serio
->
drv
))
{
ret
=
serio
->
drv
->
interrupt
(
serio
,
data
,
dfl
,
regs
);
}
else
{
if
(
!
dfl
)
{
if
((
serio
->
type
!=
SERIO_8042
&&
serio
->
type
!=
SERIO_8042_XL
)
||
(
data
==
0xaa
))
{
serio_rescan
(
serio
);
ret
=
IRQ_HANDLED
;
}
}
}
spin_unlock_irqrestore
(
&
serio
->
lock
,
flags
);
pid
=
kernel_thread
(
serio_thread
,
NULL
,
CLONE_KERNEL
);
return
ret
;
}
if
(
!
pid
)
{
static
int
__init
serio_init
(
void
)
{
if
(
!
(
serio_pid
=
kernel_thread
(
serio_thread
,
NULL
,
CLONE_KERNEL
)))
{
printk
(
KERN_WARNING
"serio: Failed to start kseriod
\n
"
);
return
-
1
;
}
serio_pid
=
pid
;
serio_bus
.
dev_attrs
=
serio_device_attrs
;
serio_bus
.
drv_attrs
=
serio_driver_attrs
;
bus_register
(
&
serio_bus
);
return
0
;
}
static
void
__exit
serio_exit
(
void
)
{
bus_unregister
(
&
serio_bus
);
kill_proc
(
serio_pid
,
SIGTERM
,
1
);
wait_for_completion
(
&
serio_exited
);
}
...
...
drivers/input/serio/serio_raw.c
0 → 100644
View file @
73df7566
/*
* Raw serio device providing access to a raw byte stream from underlying
* serio port. Closely emulates behavior of pre-2.6 /dev/psaux device
*
* Copyright (c) 2004 Dmitry Torokhov
*
* 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.
*/
#include <linux/slab.h>
#include <linux/poll.h>
#include <linux/module.h>
#include <linux/serio.h>
#include <linux/init.h>
#include <linux/major.h>
#include <linux/device.h>
#include <linux/devfs_fs_kernel.h>
#include <linux/miscdevice.h>
#include <linux/wait.h>
#define DRIVER_DESC "Raw serio driver"
MODULE_AUTHOR
(
"Dmitry Torokhov <dtor@mail.ru>"
);
MODULE_DESCRIPTION
(
DRIVER_DESC
);
MODULE_LICENSE
(
"GPL"
);
#define SERIO_RAW_QUEUE_LEN 64
struct
serio_raw
{
unsigned
char
queue
[
SERIO_RAW_QUEUE_LEN
];
unsigned
int
tail
,
head
;
char
name
[
16
];
unsigned
int
refcnt
;
struct
serio
*
serio
;
struct
miscdevice
dev
;
wait_queue_head_t
wait
;
struct
list_head
list
;
struct
list_head
node
;
};
struct
serio_raw_list
{
struct
fasync_struct
*
fasync
;
struct
serio_raw
*
serio_raw
;
struct
list_head
node
;
};
static
DECLARE_MUTEX
(
serio_raw_sem
);
static
LIST_HEAD
(
serio_raw_list
);
static
unsigned
int
serio_raw_no
;
/*********************************************************************
* Interface with userspace (file operations) *
*********************************************************************/
static
int
serio_raw_fasync
(
int
fd
,
struct
file
*
file
,
int
on
)
{
struct
serio_raw_list
*
list
=
file
->
private_data
;
int
retval
;
retval
=
fasync_helper
(
fd
,
file
,
on
,
&
list
->
fasync
);
return
retval
<
0
?
retval
:
0
;
}
static
struct
serio_raw
*
serio_raw_locate
(
int
minor
)
{
struct
serio_raw
*
serio_raw
;
list_for_each_entry
(
serio_raw
,
&
serio_raw_list
,
node
)
{
if
(
serio_raw
->
dev
.
minor
==
minor
)
return
serio_raw
;
}
return
NULL
;
}
static
int
serio_raw_open
(
struct
inode
*
inode
,
struct
file
*
file
)
{
struct
serio_raw
*
serio_raw
;
struct
serio_raw_list
*
list
;
int
retval
=
0
;
retval
=
down_interruptible
(
&
serio_raw_sem
);
if
(
retval
)
return
retval
;
if
(
!
(
serio_raw
=
serio_raw_locate
(
iminor
(
inode
))))
{
retval
=
-
ENODEV
;
goto
out
;
}
if
(
!
serio_raw
->
serio
)
{
retval
=
-
ENODEV
;
goto
out
;
}
if
(
!
(
list
=
kmalloc
(
sizeof
(
struct
serio_raw_list
),
GFP_KERNEL
)))
{
retval
=
-
ENOMEM
;
goto
out
;
}
memset
(
list
,
0
,
sizeof
(
struct
serio_raw_list
));
list
->
serio_raw
=
serio_raw
;
file
->
private_data
=
list
;
serio_raw
->
refcnt
++
;
list_add_tail
(
&
list
->
node
,
&
serio_raw
->
list
);
out:
up
(
&
serio_raw_sem
);
return
retval
;
}
static
int
serio_raw_cleanup
(
struct
serio_raw
*
serio_raw
)
{
if
(
--
serio_raw
->
refcnt
==
0
)
{
misc_deregister
(
&
serio_raw
->
dev
);
list_del_init
(
&
serio_raw
->
node
);
kfree
(
serio_raw
);
return
1
;
}
return
0
;
}
static
int
serio_raw_release
(
struct
inode
*
inode
,
struct
file
*
file
)
{
struct
serio_raw_list
*
list
=
file
->
private_data
;
struct
serio_raw
*
serio_raw
=
list
->
serio_raw
;
down
(
&
serio_raw_sem
);
serio_raw_fasync
(
-
1
,
file
,
0
);
serio_raw_cleanup
(
serio_raw
);
up
(
&
serio_raw_sem
);
return
0
;
}
static
int
serio_raw_fetch_byte
(
struct
serio_raw
*
serio_raw
,
char
*
c
)
{
unsigned
long
flags
;
int
empty
;
spin_lock_irqsave
(
&
serio_raw
->
serio
->
lock
,
flags
);
empty
=
serio_raw
->
head
==
serio_raw
->
tail
;
if
(
!
empty
)
{
*
c
=
serio_raw
->
queue
[
serio_raw
->
tail
];
serio_raw
->
tail
=
(
serio_raw
->
tail
+
1
)
%
SERIO_RAW_QUEUE_LEN
;
}
spin_unlock_irqrestore
(
&
serio_raw
->
serio
->
lock
,
flags
);
return
!
empty
;
}
static
ssize_t
serio_raw_read
(
struct
file
*
file
,
char
*
buffer
,
size_t
count
,
loff_t
*
ppos
)
{
struct
serio_raw_list
*
list
=
file
->
private_data
;
struct
serio_raw
*
serio_raw
=
list
->
serio_raw
;
char
c
;
ssize_t
retval
=
0
;
if
(
!
serio_raw
->
serio
)
return
-
ENODEV
;
if
(
serio_raw
->
head
==
serio_raw
->
tail
&&
(
file
->
f_flags
&
O_NONBLOCK
))
return
-
EAGAIN
;
retval
=
wait_event_interruptible
(
list
->
serio_raw
->
wait
,
serio_raw
->
head
!=
serio_raw
->
tail
||
!
serio_raw
->
serio
);
if
(
retval
)
return
retval
;
if
(
!
serio_raw
->
serio
)
return
-
ENODEV
;
while
(
retval
<
count
&&
serio_raw_fetch_byte
(
serio_raw
,
&
c
))
{
if
(
put_user
(
c
,
buffer
++
))
return
-
EFAULT
;
retval
++
;
}
return
retval
;
}
static
ssize_t
serio_raw_write
(
struct
file
*
file
,
const
char
*
buffer
,
size_t
count
,
loff_t
*
ppos
)
{
struct
serio_raw_list
*
list
=
file
->
private_data
;
ssize_t
written
=
0
;
int
retval
;
unsigned
char
c
;
retval
=
down_interruptible
(
&
serio_raw_sem
);
if
(
retval
)
return
retval
;
if
(
!
list
->
serio_raw
->
serio
)
{
retval
=
-
ENODEV
;
goto
out
;
}
if
(
count
>
32
)
count
=
32
;
while
(
count
--
)
{
if
(
get_user
(
c
,
buffer
++
))
{
retval
=
-
EFAULT
;
goto
out
;
}
if
(
serio_write
(
list
->
serio_raw
->
serio
,
c
))
{
retval
=
-
EIO
;
goto
out
;
}
written
++
;
};
out:
up
(
&
serio_raw_sem
);
return
written
;
}
static
unsigned
int
serio_raw_poll
(
struct
file
*
file
,
poll_table
*
wait
)
{
struct
serio_raw_list
*
list
=
file
->
private_data
;
poll_wait
(
file
,
&
list
->
serio_raw
->
wait
,
wait
);
if
(
list
->
serio_raw
->
head
!=
list
->
serio_raw
->
tail
)
return
POLLIN
|
POLLRDNORM
;
return
0
;
}
struct
file_operations
serio_raw_fops
=
{
.
owner
=
THIS_MODULE
,
.
open
=
serio_raw_open
,
.
release
=
serio_raw_release
,
.
read
=
serio_raw_read
,
.
write
=
serio_raw_write
,
.
poll
=
serio_raw_poll
,
.
fasync
=
serio_raw_fasync
,
};
/*********************************************************************
* Interface with serio port *
*********************************************************************/
static
irqreturn_t
serio_raw_interrupt
(
struct
serio
*
serio
,
unsigned
char
data
,
unsigned
int
dfl
,
struct
pt_regs
*
regs
)
{
struct
serio_raw
*
serio_raw
=
serio
->
private
;
struct
serio_raw_list
*
list
;
unsigned
int
head
=
serio_raw
->
head
;
/* we are holding serio->lock here so we are prootected */
serio_raw
->
queue
[
head
]
=
data
;
head
=
(
head
+
1
)
%
SERIO_RAW_QUEUE_LEN
;
if
(
likely
(
head
!=
serio_raw
->
tail
))
{
serio_raw
->
head
=
head
;
list_for_each_entry
(
list
,
&
serio_raw
->
list
,
node
)
kill_fasync
(
&
list
->
fasync
,
SIGIO
,
POLL_IN
);
wake_up_interruptible
(
&
serio_raw
->
wait
);
}
return
IRQ_HANDLED
;
}
static
void
serio_raw_connect
(
struct
serio
*
serio
,
struct
serio_driver
*
drv
)
{
struct
serio_raw
*
serio_raw
;
int
err
;
if
((
serio
->
type
&
SERIO_TYPE
)
!=
SERIO_8042
)
return
;
if
(
!
(
serio_raw
=
kmalloc
(
sizeof
(
struct
serio_raw
),
GFP_KERNEL
)))
{
printk
(
KERN_ERR
"serio_raw.c: can't allocate memory for a device
\n
"
);
return
;
}
down
(
&
serio_raw_sem
);
memset
(
serio_raw
,
0
,
sizeof
(
struct
serio_raw
));
snprintf
(
serio_raw
->
name
,
sizeof
(
serio_raw
->
name
),
"serio_raw%d"
,
serio_raw_no
++
);
serio_raw
->
refcnt
=
1
;
serio_raw
->
serio
=
serio
;
INIT_LIST_HEAD
(
&
serio_raw
->
list
);
init_waitqueue_head
(
&
serio_raw
->
wait
);
serio
->
private
=
serio_raw
;
if
(
serio_open
(
serio
,
drv
))
goto
out_free
;
list_add_tail
(
&
serio_raw
->
node
,
&
serio_raw_list
);
serio_raw
->
dev
.
minor
=
PSMOUSE_MINOR
;
serio_raw
->
dev
.
name
=
serio_raw
->
name
;
serio_raw
->
dev
.
fops
=
&
serio_raw_fops
;
err
=
misc_register
(
&
serio_raw
->
dev
);
if
(
err
)
{
serio_raw
->
dev
.
minor
=
MISC_DYNAMIC_MINOR
;
err
=
misc_register
(
&
serio_raw
->
dev
);
}
if
(
err
)
{
printk
(
KERN_INFO
"serio_raw: failed to register raw access device for %s
\n
"
,
serio
->
phys
);
goto
out_close
;
}
printk
(
KERN_INFO
"serio_raw: raw access enabled on %s (%s, minor %d)
\n
"
,
serio
->
phys
,
serio_raw
->
name
,
serio_raw
->
dev
.
minor
);
goto
out
;
out_close:
serio_close
(
serio
);
list_del_init
(
&
serio_raw
->
node
);
out_free:
serio
->
private
=
NULL
;
kfree
(
serio_raw
);
out:
up
(
&
serio_raw_sem
);
}
static
int
serio_raw_reconnect
(
struct
serio
*
serio
)
{
struct
serio_raw
*
serio_raw
=
serio
->
private
;
struct
serio_driver
*
drv
=
serio
->
drv
;
if
(
!
drv
||
!
serio_raw
)
{
printk
(
KERN_DEBUG
"serio_raw: reconnect request, but serio is disconnected, ignoring...
\n
"
);
return
-
1
;
}
/*
* Nothing needs to be done here, we just need this method to
* keep the same device.
*/
return
0
;
}
static
void
serio_raw_disconnect
(
struct
serio
*
serio
)
{
struct
serio_raw
*
serio_raw
;
down
(
&
serio_raw_sem
);
serio_raw
=
serio
->
private
;
serio_close
(
serio
);
serio
->
private
=
NULL
;
serio_raw
->
serio
=
NULL
;
if
(
!
serio_raw_cleanup
(
serio_raw
))
wake_up_interruptible
(
&
serio_raw
->
wait
);
up
(
&
serio_raw_sem
);
}
static
struct
serio_driver
serio_raw_drv
=
{
.
driver
=
{
.
name
=
"serio_raw"
,
},
.
description
=
DRIVER_DESC
,
.
interrupt
=
serio_raw_interrupt
,
.
connect
=
serio_raw_connect
,
.
reconnect
=
serio_raw_reconnect
,
.
disconnect
=
serio_raw_disconnect
,
.
manual_bind
=
1
,
};
int
__init
serio_raw_init
(
void
)
{
serio_register_driver
(
&
serio_raw_drv
);
return
0
;
}
void
__exit
serio_raw_exit
(
void
)
{
serio_unregister_driver
(
&
serio_raw_drv
);
}
module_init
(
serio_raw_init
);
module_exit
(
serio_raw_exit
);
drivers/input/serio/serport.c
View file @
73df7566
...
...
@@ -31,28 +31,25 @@ MODULE_ALIAS_LDISC(N_MOUSE);
struct
serport
{
struct
tty_struct
*
tty
;
wait_queue_head_t
wait
;
struct
serio
serio
;
struct
serio
*
serio
;
unsigned
long
flags
;
char
phys
[
32
];
};
char
serport_name
[]
=
"Serial port"
;
/*
* Callback functions from the serio code.
*/
static
int
serport_serio_write
(
struct
serio
*
serio
,
unsigned
char
data
)
{
struct
serport
*
serport
=
serio
->
driver
;
struct
serport
*
serport
=
serio
->
port_data
;
return
-
(
serport
->
tty
->
driver
->
write
(
serport
->
tty
,
0
,
&
data
,
1
)
!=
1
);
}
static
void
serport_serio_close
(
struct
serio
*
serio
)
{
struct
serport
*
serport
=
serio
->
driver
;
struct
serport
*
serport
=
serio
->
port_data
;
serport
->
serio
.
type
=
0
;
serport
->
serio
->
type
=
0
;
wake_up_interruptible
(
&
serport
->
wait
);
}
...
...
@@ -64,26 +61,30 @@ static void serport_serio_close(struct serio *serio)
static
int
serport_ldisc_open
(
struct
tty_struct
*
tty
)
{
struct
serport
*
serport
;
struct
serio
*
serio
;
char
name
[
64
];
serport
=
kmalloc
(
sizeof
(
struct
serport
),
GFP_KERNEL
);
if
(
unlikely
(
!
serport
))
serio
=
kmalloc
(
sizeof
(
struct
serio
),
GFP_KERNEL
);
if
(
unlikely
(
!
serport
||
!
serio
))
{
kfree
(
serport
);
kfree
(
serio
);
return
-
ENOMEM
;
memset
(
serport
,
0
,
sizeof
(
struct
serport
));
}
memset
(
serport
,
0
,
sizeof
(
struct
serport
));
serport
->
serio
=
serio
;
set_bit
(
TTY_DO_WRITE_WAKEUP
,
&
tty
->
flags
);
serport
->
tty
=
tty
;
tty
->
disc_data
=
serport
;
snprintf
(
serport
->
phys
,
sizeof
(
serport
->
phys
),
"%s/serio0"
,
tty_name
(
tty
,
name
));
serport
->
serio
.
name
=
serport_name
;
serport
->
serio
.
phys
=
serport
->
phys
;
serport
->
serio
.
type
=
SERIO_RS232
;
serport
->
serio
.
write
=
serport_serio_write
;
serport
->
serio
.
close
=
serport_serio_close
;
serport
->
serio
.
driver
=
serport
;
memset
(
serio
,
0
,
sizeof
(
struct
serio
));
strlcpy
(
serio
->
name
,
"Serial port"
,
sizeof
(
serio
->
name
));
snprintf
(
serio
->
phys
,
sizeof
(
serio
->
phys
),
"%s/serio0"
,
tty_name
(
tty
,
name
));
serio
->
type
=
SERIO_RS232
;
serio
->
write
=
serport_serio_write
;
serio
->
close
=
serport_serio_close
;
serio
->
port_data
=
serport
;
init_waitqueue_head
(
&
serport
->
wait
);
...
...
@@ -114,7 +115,7 @@ static void serport_ldisc_receive(struct tty_struct *tty, const unsigned char *c
struct
serport
*
serport
=
(
struct
serport
*
)
tty
->
disc_data
;
int
i
;
for
(
i
=
0
;
i
<
count
;
i
++
)
serio_interrupt
(
&
serport
->
serio
,
cp
[
i
],
0
,
NULL
);
serio_interrupt
(
serport
->
serio
,
cp
[
i
],
0
,
NULL
);
}
/*
...
...
@@ -142,10 +143,10 @@ static ssize_t serport_ldisc_read(struct tty_struct * tty, struct file * file, u
if
(
test_and_set_bit
(
SERPORT_BUSY
,
&
serport
->
flags
))
return
-
EBUSY
;
serio_register_port
(
&
serport
->
serio
);
serio_register_port
(
serport
->
serio
);
printk
(
KERN_INFO
"serio: Serial port %s
\n
"
,
tty_name
(
tty
,
name
));
wait_event_interruptible
(
serport
->
wait
,
!
serport
->
serio
.
type
);
serio_unregister_port
(
&
serport
->
serio
);
wait_event_interruptible
(
serport
->
wait
,
!
serport
->
serio
->
type
);
serio_unregister_port
(
serport
->
serio
);
clear_bit
(
SERPORT_BUSY
,
&
serport
->
flags
);
...
...
@@ -161,7 +162,7 @@ static int serport_ldisc_ioctl(struct tty_struct * tty, struct file * file, unsi
struct
serport
*
serport
=
(
struct
serport
*
)
tty
->
disc_data
;
if
(
cmd
==
SPIOCSTYPE
)
return
get_user
(
serport
->
serio
.
type
,
(
unsigned
long
__user
*
)
arg
);
return
get_user
(
serport
->
serio
->
type
,
(
unsigned
long
__user
*
)
arg
);
return
-
EINVAL
;
}
...
...
@@ -170,7 +171,7 @@ static void serport_ldisc_write_wakeup(struct tty_struct * tty)
{
struct
serport
*
sp
=
(
struct
serport
*
)
tty
->
disc_data
;
serio_d
ev_write_wakeup
(
&
sp
->
serio
);
serio_d
rv_write_wakeup
(
sp
->
serio
);
}
/*
...
...
drivers/input/touchscreen/gunze.c
View file @
73df7566
...
...
@@ -36,8 +36,10 @@
#include <linux/serio.h>
#include <linux/init.h>
#define DRIVER_DESC "Gunze AHL-51S touchscreen driver"
MODULE_AUTHOR
(
"Vojtech Pavlik <vojtech@ucw.cz>"
);
MODULE_DESCRIPTION
(
"Gunze AHL-51S touchscreen driver"
);
MODULE_DESCRIPTION
(
DRIVER_DESC
);
MODULE_LICENSE
(
"GPL"
);
/*
...
...
@@ -111,7 +113,7 @@ static void gunze_disconnect(struct serio *serio)
* and if yes, registers it as an input device.
*/
static
void
gunze_connect
(
struct
serio
*
serio
,
struct
serio_d
ev
*
de
v
)
static
void
gunze_connect
(
struct
serio
*
serio
,
struct
serio_d
river
*
dr
v
)
{
struct
gunze
*
gunze
;
...
...
@@ -142,7 +144,7 @@ static void gunze_connect(struct serio *serio, struct serio_dev *dev)
gunze
->
dev
.
id
.
product
=
0x0051
;
gunze
->
dev
.
id
.
version
=
0x0100
;
if
(
serio_open
(
serio
,
d
e
v
))
{
if
(
serio_open
(
serio
,
d
r
v
))
{
kfree
(
gunze
);
return
;
}
...
...
@@ -156,10 +158,14 @@ static void gunze_connect(struct serio *serio, struct serio_dev *dev)
* The serio device structure.
*/
static
struct
serio_dev
gunze_dev
=
{
.
interrupt
=
gunze_interrupt
,
.
connect
=
gunze_connect
,
.
disconnect
=
gunze_disconnect
,
static
struct
serio_driver
gunze_drv
=
{
.
driver
=
{
.
name
=
"gunze"
,
},
.
description
=
DRIVER_DESC
,
.
interrupt
=
gunze_interrupt
,
.
connect
=
gunze_connect
,
.
disconnect
=
gunze_disconnect
,
};
/*
...
...
@@ -168,13 +174,13 @@ static struct serio_dev gunze_dev = {
int
__init
gunze_init
(
void
)
{
serio_register_d
evice
(
&
gunze_de
v
);
serio_register_d
river
(
&
gunze_dr
v
);
return
0
;
}
void
__exit
gunze_exit
(
void
)
{
serio_unregister_d
evice
(
&
gunze_de
v
);
serio_unregister_d
river
(
&
gunze_dr
v
);
}
module_init
(
gunze_init
);
...
...
drivers/input/touchscreen/h3600_ts_input.c
View file @
73df7566
...
...
@@ -45,8 +45,10 @@
#include <asm/arch/hardware.h>
#include <asm/arch/irqs.h>
#define DRIVER_DESC "H3600 touchscreen driver"
MODULE_AUTHOR
(
"James Simmons <jsimmons@transvirtual.com>"
);
MODULE_DESCRIPTION
(
"H3600 touchscreen driver"
);
MODULE_DESCRIPTION
(
DRIVER_DESC
);
MODULE_LICENSE
(
"GPL"
);
/*
...
...
@@ -373,7 +375,7 @@ static irqreturn_t h3600ts_interrupt(struct serio *serio, unsigned char data,
* new serio device. It looks whether it was registered as a H3600 touchscreen
* and if yes, registers it as an input device.
*/
static
void
h3600ts_connect
(
struct
serio
*
serio
,
struct
serio_d
ev
*
de
v
)
static
void
h3600ts_connect
(
struct
serio
*
serio
,
struct
serio_d
river
*
dr
v
)
{
struct
h3600_dev
*
ts
;
...
...
@@ -441,7 +443,7 @@ static void h3600ts_connect(struct serio *serio, struct serio_dev *dev)
ts
->
dev
.
id
.
product
=
0x0666
;
/* FIXME !!! We can ask the hardware */
ts
->
dev
.
id
.
version
=
0x0100
;
if
(
serio_open
(
serio
,
d
e
v
))
{
if
(
serio_open
(
serio
,
d
r
v
))
{
free_irq
(
IRQ_GPIO_BITSY_ACTION_BUTTON
,
ts
);
free_irq
(
IRQ_GPIO_BITSY_NPOWER_BUTTON
,
ts
);
kfree
(
ts
);
...
...
@@ -478,10 +480,14 @@ static void h3600ts_disconnect(struct serio *serio)
* The serio device structure.
*/
static
struct
serio_dev
h3600ts_dev
=
{
.
interrupt
=
h3600ts_interrupt
,
.
connect
=
h3600ts_connect
,
.
disconnect
=
h3600ts_disconnect
,
static
struct
serio_driver
h3600ts_drv
=
{
.
driver
=
{
.
name
=
"h3600ts"
,
},
.
description
=
DRIVER_DESC
,
.
interrupt
=
h3600ts_interrupt
,
.
connect
=
h3600ts_connect
,
.
disconnect
=
h3600ts_disconnect
,
};
/*
...
...
@@ -490,13 +496,13 @@ static struct serio_dev h3600ts_dev = {
static
int
__init
h3600ts_init
(
void
)
{
serio_register_d
evice
(
&
h3600ts_de
v
);
serio_register_d
river
(
&
h3600ts_dr
v
);
return
0
;
}
static
void
__exit
h3600ts_exit
(
void
)
{
serio_unregister_d
evice
(
&
h3600ts_de
v
);
serio_unregister_d
river
(
&
h3600ts_dr
v
);
}
module_init
(
h3600ts_init
);
...
...
drivers/input/tsdev.c
View file @
73df7566
...
...
@@ -3,32 +3,42 @@
*
* Copyright (c) 2001 "Crazy" james Simmons
*
* Input driver to Touchscreen device driver module.
* Compaq touchscreen protocol driver. The protocol emulated by this driver
* is obsolete; for new programs use the tslib library which can read directly
* from evdev and perform dejittering, variance filtering and calibration -
* all in user space, not at kernel level. The meaning of this driver is
* to allow usage of newer input drivers with old applications that use the
* old /dev/h3600_ts and /dev/h3600_tsraw devices.
*
* Sponsored by Transvirtual Technology
* 09-Apr-2004: Andrew Zabolotny <zap@homelink.ru>
* Fixed to actually work, not just output random numbers.
* Added support for both h3600_ts and h3600_tsraw protocol
* emulation.
*/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*
* Should you need to contact me, the author, you can do so either by
* e-mail - mail your message to <jsimmons@
transvirtual.com
>.
* e-mail - mail your message to <jsimmons@
infradead.org
>.
*/
#define TSDEV_MINOR_BASE 128
#define TSDEV_MINORS 32
/* First 16 devices are h3600_ts compatible; second 16 are h3600_tsraw */
#define TSDEV_MINOR_MASK 15
#define TSDEV_BUFFER_SIZE 64
#include <linux/slab.h>
...
...
@@ -52,48 +62,84 @@
#define CONFIG_INPUT_TSDEV_SCREEN_Y 320
#endif
/* This driver emulates both protocols of the old h3600_ts and h3600_tsraw
* devices. The first one must output X/Y data in 'cooked' format, e.g.
* filtered, dejittered and calibrated. Second device just outputs raw
* data received from the hardware.
*
* This driver doesn't support filtering and dejittering; it supports only
* calibration. Filtering and dejittering must be done in the low-level
* driver, if needed, because it may gain additional benefits from knowing
* the low-level details, the nature of noise and so on.
*
* The driver precomputes a calibration matrix given the initial xres and
* yres values (quite innacurate for most touchscreens) that will result
* in a more or less expected range of output values. The driver supports
* the TS_SET_CAL ioctl, which will replace the calibration matrix with a
* new one, supposedly generated from the values taken from the raw device.
*/
MODULE_AUTHOR
(
"James Simmons <jsimmons@transvirtual.com>"
);
MODULE_DESCRIPTION
(
"Input driver to touchscreen converter"
);
MODULE_LICENSE
(
"GPL"
);
static
int
xres
=
CONFIG_INPUT_TSDEV_SCREEN_X
;
module_param
(
xres
,
uint
,
0
);
MODULE_PARM_DESC
(
xres
,
"Horizontal screen resolution"
);
MODULE_PARM_DESC
(
xres
,
"Horizontal screen resolution
(can be negative for X-mirror)
"
);
static
int
yres
=
CONFIG_INPUT_TSDEV_SCREEN_Y
;
module_param
(
yres
,
uint
,
0
);
MODULE_PARM_DESC
(
yres
,
"Vertical screen resolution"
);
MODULE_PARM_DESC
(
yres
,
"Vertical screen resolution (can be negative for Y-mirror)"
);
/* From Compaq's Touch Screen Specification version 0.2 (draft) */
struct
ts_event
{
short
pressure
;
short
x
;
short
y
;
short
millisecs
;
};
struct
ts_calibration
{
int
xscale
;
int
xtrans
;
int
yscale
;
int
ytrans
;
int
xyswap
;
};
struct
tsdev
{
int
exist
;
int
open
;
int
minor
;
char
name
[
16
];
char
name
[
8
];
wait_queue_head_t
wait
;
struct
list_head
list
;
struct
input_handle
handle
;
int
x
,
y
,
pressure
;
struct
ts_calibration
cal
;
};
/* From Compaq's Touch Screen Specification version 0.2 (draft) */
typedef
struct
{
short
pressure
;
short
x
;
short
y
;
short
millisecs
;
}
TS_EVENT
;
struct
tsdev_list
{
struct
fasync_struct
*
fasync
;
struct
list_head
node
;
struct
tsdev
*
tsdev
;
int
head
,
tail
;
int
oldx
,
oldy
,
pendown
;
TS_EVENT
event
[
TSDEV_BUFFER_SIZE
]
;
struct
ts_event
event
[
TSDEV_BUFFER_SIZE
]
;
int
raw
;
};
/* The following ioctl codes are defined ONLY for backward compatibility.
* Don't use tsdev for new developement; use the tslib library instead.
* Touchscreen calibration is a fully userspace task.
*/
/* Use 'f' as magic number */
#define IOC_H3600_TS_MAGIC 'f'
#define TS_GET_CAL _IOR(IOC_H3600_TS_MAGIC, 10, struct ts_calibration)
#define TS_SET_CAL _IOW(IOC_H3600_TS_MAGIC, 11, struct ts_calibration)
static
struct
input_handler
tsdev_handler
;
static
struct
tsdev
*
tsdev_table
[
TSDEV_MINORS
];
static
struct
tsdev
*
tsdev_table
[
TSDEV_MINORS
/
2
];
static
int
tsdev_fasync
(
int
fd
,
struct
file
*
file
,
int
on
)
{
...
...
@@ -109,13 +155,16 @@ static int tsdev_open(struct inode *inode, struct file *file)
int
i
=
iminor
(
inode
)
-
TSDEV_MINOR_BASE
;
struct
tsdev_list
*
list
;
if
(
i
>=
TSDEV_MINORS
||
!
tsdev_table
[
i
])
if
(
i
>=
TSDEV_MINORS
||
!
tsdev_table
[
i
&
TSDEV_MINOR_MASK
])
return
-
ENODEV
;
if
(
!
(
list
=
kmalloc
(
sizeof
(
struct
tsdev_list
),
GFP_KERNEL
)))
return
-
ENOMEM
;
memset
(
list
,
0
,
sizeof
(
struct
tsdev_list
));
list
->
raw
=
(
i
>=
TSDEV_MINORS
/
2
)
?
1
:
0
;
i
&=
TSDEV_MINOR_MASK
;
list
->
tsdev
=
tsdev_table
[
i
];
list_add_tail
(
&
list
->
node
,
&
tsdev_table
[
i
]
->
list
);
file
->
private_data
=
list
;
...
...
@@ -161,7 +210,7 @@ static ssize_t tsdev_read(struct file *file, char __user *buffer, size_t count,
return
-
EAGAIN
;
retval
=
wait_event_interruptible
(
list
->
tsdev
->
wait
,
(
list
->
head
!=
list
->
tail
)
&&
list
->
tsdev
->
exist
);
list
->
head
!=
list
->
tail
||
!
list
->
tsdev
->
exist
);
if
(
retval
)
return
retval
;
...
...
@@ -169,11 +218,13 @@ static ssize_t tsdev_read(struct file *file, char __user *buffer, size_t count,
if
(
!
list
->
tsdev
->
exist
)
return
-
ENODEV
;
while
(
list
->
head
!=
list
->
tail
&&
retval
+
sizeof
(
TS_EVENT
)
<=
count
)
{
if
(
copy_to_user
(
buffer
+
retval
,
list
->
event
+
list
->
tail
,
sizeof
(
TS_EVENT
)))
while
(
list
->
head
!=
list
->
tail
&&
retval
+
sizeof
(
struct
ts_event
)
<=
count
)
{
if
(
copy_to_user
(
buffer
+
retval
,
list
->
event
+
list
->
tail
,
sizeof
(
struct
ts_event
)))
return
-
EFAULT
;
list
->
tail
=
(
list
->
tail
+
1
)
&
(
TSDEV_BUFFER_SIZE
-
1
);
retval
+=
sizeof
(
TS_EVENT
);
retval
+=
sizeof
(
struct
ts_event
);
}
return
retval
;
...
...
@@ -193,22 +244,27 @@ static unsigned int tsdev_poll(struct file *file, poll_table * wait)
static
int
tsdev_ioctl
(
struct
inode
*
inode
,
struct
file
*
file
,
unsigned
int
cmd
,
unsigned
long
arg
)
{
/*
struct
tsdev_list
*
list
=
file
->
private_data
;
struct tsdev *evdev = list->tsdev;
struct input_dev *dev = tsdev->handle.dev;
int retval;
struct
tsdev
*
tsdev
=
list
->
tsdev
;
int
retval
=
0
;
switch
(
cmd
)
{
case HHEHE:
return 0;
case hjff:
return 0;
default:
return 0;
case
TS_GET_CAL
:
if
(
copy_to_user
((
void
*
)
arg
,
&
tsdev
->
cal
,
sizeof
(
struct
ts_calibration
)))
retval
=
-
EFAULT
;
break
;
case
TS_SET_CAL
:
if
(
copy_from_user
(
&
tsdev
->
cal
,
(
void
*
)
arg
,
sizeof
(
struct
ts_calibration
)))
retval
=
-
EFAULT
;
break
;
default:
retval
=
-
EINVAL
;
break
;
}
*/
return
-
EINVAL
;
return
retval
;
}
struct
file_operations
tsdev_fops
=
{
...
...
@@ -227,82 +283,85 @@ static void tsdev_event(struct input_handle *handle, unsigned int type,
struct
tsdev
*
tsdev
=
handle
->
private
;
struct
tsdev_list
*
list
;
struct
timeval
time
;
int
size
;
list_for_each_entry
(
list
,
&
tsdev
->
list
,
node
)
{
switch
(
type
)
{
case
EV_ABS
:
switch
(
code
)
{
case
ABS_X
:
if
(
!
list
->
pendown
)
return
;
size
=
handle
->
dev
->
absmax
[
ABS_X
]
-
handle
->
dev
->
absmin
[
ABS_X
];
if
(
size
>
0
)
list
->
oldx
=
((
value
-
handle
->
dev
->
absmin
[
ABS_X
])
*
xres
/
size
);
else
list
->
oldx
=
((
value
-
handle
->
dev
->
absmin
[
ABS_X
]));
break
;
case
ABS_Y
:
if
(
!
list
->
pendown
)
return
;
size
=
handle
->
dev
->
absmax
[
ABS_Y
]
-
handle
->
dev
->
absmin
[
ABS_Y
];
if
(
size
>
0
)
list
->
oldy
=
((
value
-
handle
->
dev
->
absmin
[
ABS_Y
])
*
yres
/
size
);
else
list
->
oldy
=
((
value
-
handle
->
dev
->
absmin
[
ABS_Y
]));
break
;
case
ABS_PRESSURE
:
list
->
pendown
=
((
value
>
handle
->
dev
->
absmin
[
ABS_PRESSURE
]))
?
value
-
handle
->
dev
->
absmin
[
ABS_PRESSURE
]
:
0
;
break
;
}
switch
(
type
)
{
case
EV_ABS
:
switch
(
code
)
{
case
ABS_X
:
tsdev
->
x
=
value
;
break
;
case
ABS_Y
:
tsdev
->
y
=
value
;
break
;
case
ABS_PRESSURE
:
if
(
value
>
handle
->
dev
->
absmax
[
ABS_PRESSURE
])
value
=
handle
->
dev
->
absmax
[
ABS_PRESSURE
];
value
-=
handle
->
dev
->
absmin
[
ABS_PRESSURE
];
if
(
value
<
0
)
value
=
0
;
tsdev
->
pressure
=
value
;
break
;
}
break
;
case
EV_REL
:
switch
(
code
)
{
case
REL_X
:
tsdev
->
x
+=
value
;
if
(
tsdev
->
x
<
0
)
tsdev
->
x
=
0
;
else
if
(
tsdev
->
x
>
xres
)
tsdev
->
x
=
xres
;
break
;
case
REL_Y
:
tsdev
->
y
+=
value
;
if
(
tsdev
->
y
<
0
)
tsdev
->
y
=
0
;
else
if
(
tsdev
->
y
>
yres
)
tsdev
->
y
=
yres
;
break
;
}
break
;
case
EV_REL
:
switch
(
code
)
{
case
REL_X
:
if
(
!
list
->
pendown
)
return
;
list
->
oldx
+=
value
;
if
(
list
->
oldx
<
0
)
list
->
oldx
=
0
;
else
if
(
list
->
oldx
>
xres
)
list
->
oldx
=
xres
;
case
EV_KEY
:
if
(
code
==
BTN_TOUCH
||
code
==
BTN_MOUSE
)
{
switch
(
value
)
{
case
0
:
tsdev
->
pressure
=
0
;
break
;
case
REL_Y
:
if
(
!
list
->
pendown
)
return
;
list
->
oldy
+=
value
;
if
(
list
->
oldy
<
0
)
list
->
oldy
=
0
;
else
if
(
list
->
oldy
>
xres
)
list
->
oldy
=
xres
;
case
1
:
if
(
!
tsdev
->
pressure
)
tsdev
->
pressure
=
1
;
break
;
}
break
;
case
EV_KEY
:
if
(
code
==
BTN_TOUCH
||
code
==
BTN_MOUSE
)
{
switch
(
value
)
{
case
0
:
list
->
pendown
=
0
;
break
;
case
1
:
if
(
!
list
->
pendown
)
list
->
pendown
=
1
;
break
;
case
2
:
return
;
}
}
else
return
;
break
;
}
break
;
}
if
(
type
!=
EV_SYN
||
code
!=
SYN_REPORT
)
return
;
list_for_each_entry
(
list
,
&
tsdev
->
list
,
node
)
{
int
x
,
y
,
tmp
;
do_gettimeofday
(
&
time
);
list
->
event
[
list
->
head
].
millisecs
=
time
.
tv_usec
/
100
;
list
->
event
[
list
->
head
].
pressure
=
list
->
pendown
;
list
->
event
[
list
->
head
].
x
=
list
->
oldx
;
list
->
event
[
list
->
head
].
y
=
list
->
oldy
;
list
->
event
[
list
->
head
].
pressure
=
tsdev
->
pressure
;
x
=
tsdev
->
x
;
y
=
tsdev
->
y
;
/* Calibration */
if
(
!
list
->
raw
)
{
x
=
((
x
*
tsdev
->
cal
.
xscale
)
>>
8
)
+
tsdev
->
cal
.
xtrans
;
y
=
((
y
*
tsdev
->
cal
.
yscale
)
>>
8
)
+
tsdev
->
cal
.
ytrans
;
if
(
tsdev
->
cal
.
xyswap
)
{
tmp
=
x
;
x
=
y
;
y
=
tmp
;
}
}
list
->
event
[
list
->
head
].
x
=
x
;
list
->
event
[
list
->
head
].
y
=
y
;
list
->
head
=
(
list
->
head
+
1
)
&
(
TSDEV_BUFFER_SIZE
-
1
);
kill_fasync
(
&
list
->
fasync
,
SIGIO
,
POLL_IN
);
}
...
...
@@ -314,11 +373,11 @@ static struct input_handle *tsdev_connect(struct input_handler *handler,
struct
input_device_id
*
id
)
{
struct
tsdev
*
tsdev
;
int
minor
;
int
minor
,
delta
;
for
(
minor
=
0
;
minor
<
TSDEV_MINORS
&&
tsdev_table
[
minor
];
for
(
minor
=
0
;
minor
<
TSDEV_MINORS
/
2
&&
tsdev_table
[
minor
];
minor
++
);
if
(
minor
==
TSDEV_MINORS
)
{
if
(
minor
>=
TSDEV_MINORS
/
2
)
{
printk
(
KERN_ERR
"tsdev: You have way too many touchscreens
\n
"
);
return
NULL
;
...
...
@@ -340,10 +399,25 @@ static struct input_handle *tsdev_connect(struct input_handler *handler,
tsdev
->
handle
.
handler
=
handler
;
tsdev
->
handle
.
private
=
tsdev
;
/* Precompute the rough calibration matrix */
delta
=
dev
->
absmax
[
ABS_X
]
-
dev
->
absmin
[
ABS_X
]
+
1
;
if
(
delta
==
0
)
delta
=
1
;
tsdev
->
cal
.
xscale
=
(
xres
<<
8
)
/
delta
;
tsdev
->
cal
.
xtrans
=
-
((
dev
->
absmin
[
ABS_X
]
*
tsdev
->
cal
.
xscale
)
>>
8
);
delta
=
dev
->
absmax
[
ABS_Y
]
-
dev
->
absmin
[
ABS_Y
]
+
1
;
if
(
delta
==
0
)
delta
=
1
;
tsdev
->
cal
.
yscale
=
(
yres
<<
8
)
/
delta
;
tsdev
->
cal
.
ytrans
=
-
((
dev
->
absmin
[
ABS_Y
]
*
tsdev
->
cal
.
yscale
)
>>
8
);
tsdev_table
[
minor
]
=
tsdev
;
devfs_mk_cdev
(
MKDEV
(
INPUT_MAJOR
,
TSDEV_MINOR_BASE
+
minor
),
S_IFCHR
|
S_IRUGO
|
S_IWUSR
,
"input/ts%d"
,
minor
);
devfs_mk_cdev
(
MKDEV
(
INPUT_MAJOR
,
TSDEV_MINOR_BASE
+
minor
+
TSDEV_MINORS
/
2
),
S_IFCHR
|
S_IRUGO
|
S_IWUSR
,
"input/tsraw%d"
,
minor
);
class_simple_device_add
(
input_class
,
MKDEV
(
INPUT_MAJOR
,
TSDEV_MINOR_BASE
+
minor
),
dev
->
dev
,
"ts%d"
,
minor
);
...
...
@@ -362,6 +436,7 @@ static void tsdev_disconnect(struct input_handle *handle)
wake_up_interruptible
(
&
tsdev
->
wait
);
}
else
tsdev_free
(
tsdev
);
devfs_remove
(
"input/tsraw%d"
,
tsdev
->
minor
);
}
static
struct
input_device_id
tsdev_ids
[]
=
{
...
...
@@ -379,6 +454,12 @@ static struct input_device_id tsdev_ids[] = {
.
absbit
=
{
BIT
(
ABS_X
)
|
BIT
(
ABS_Y
)
},
},
/* A tablet like device, at least touch detection, two absolute axes */
{
.
flags
=
INPUT_DEVICE_ID_MATCH_EVBIT
|
INPUT_DEVICE_ID_MATCH_ABSBIT
,
.
evbit
=
{
BIT
(
EV_ABS
)
},
.
absbit
=
{
BIT
(
ABS_X
)
|
BIT
(
ABS_Y
)
|
BIT
(
ABS_PRESSURE
)
},
},
/* A tablet like device with several gradations of pressure */
{},
/* Terminating entry */
};
...
...
drivers/serial/sunsu.c
View file @
73df7566
...
...
@@ -98,7 +98,7 @@ struct uart_sunsu_port {
unsigned
int
irq
;
#ifdef CONFIG_SERIO
struct
serio
serio
;
struct
serio
*
serio
;
int
serio_open
;
#endif
};
...
...
@@ -520,7 +520,7 @@ static void receive_kbd_ms_chars(struct uart_sunsu_port *up, struct pt_regs *reg
/* Stop-A is handled by drivers/char/keyboard.c now. */
if
(
up
->
su_type
==
SU_PORT_KBD
)
{
#ifdef CONFIG_SERIO
serio_interrupt
(
&
up
->
serio
,
ch
,
0
,
regs
);
serio_interrupt
(
up
->
serio
,
ch
,
0
,
regs
);
#endif
}
else
if
(
up
->
su_type
==
SU_PORT_MS
)
{
int
ret
=
suncore_mouse_baud_detection
(
ch
,
is_break
);
...
...
@@ -534,7 +534,7 @@ static void receive_kbd_ms_chars(struct uart_sunsu_port *up, struct pt_regs *reg
case
0
:
#ifdef CONFIG_SERIO
serio_interrupt
(
&
up
->
serio
,
ch
,
0
,
regs
);
serio_interrupt
(
up
->
serio
,
ch
,
0
,
regs
);
#endif
break
;
};
...
...
@@ -994,7 +994,7 @@ static spinlock_t sunsu_serio_lock = SPIN_LOCK_UNLOCKED;
static
int
sunsu_serio_write
(
struct
serio
*
serio
,
unsigned
char
ch
)
{
struct
uart_sunsu_port
*
up
=
serio
->
driver
;
struct
uart_sunsu_port
*
up
=
serio
->
port_data
;
unsigned
long
flags
;
int
lsr
;
...
...
@@ -1014,7 +1014,7 @@ static int sunsu_serio_write(struct serio *serio, unsigned char ch)
static
int
sunsu_serio_open
(
struct
serio
*
serio
)
{
struct
uart_sunsu_port
*
up
=
serio
->
driver
;
struct
uart_sunsu_port
*
up
=
serio
->
port_data
;
unsigned
long
flags
;
int
ret
;
...
...
@@ -1031,7 +1031,7 @@ static int sunsu_serio_open(struct serio *serio)
static
void
sunsu_serio_close
(
struct
serio
*
serio
)
{
struct
uart_sunsu_port
*
up
=
serio
->
driver
;
struct
uart_sunsu_port
*
up
=
serio
->
port_data
;
unsigned
long
flags
;
spin_lock_irqsave
(
&
sunsu_serio_lock
,
flags
);
...
...
@@ -1284,54 +1284,58 @@ static struct uart_driver sunsu_reg = {
.
major
=
TTY_MAJOR
,
};
static
int
__init
sunsu_kbd_ms_init
(
void
)
static
int
__init
sunsu_kbd_ms_init
(
struct
uart_sunsu_port
*
up
,
int
channel
)
{
struct
uart_sunsu_port
*
up
;
int
i
;
struct
serio
*
serio
;
for
(
i
=
0
,
up
=
sunsu_ports
;
i
<
2
;
i
++
,
up
++
)
{
up
->
port
.
line
=
i
;
up
->
port
.
type
=
PORT_UNKNOWN
;
up
->
port
.
uartclk
=
(
SU_BASE_BAUD
*
16
);
up
->
port
.
line
=
channel
;
up
->
port
.
type
=
PORT_UNKNOWN
;
up
->
port
.
uartclk
=
(
SU_BASE_BAUD
*
16
);
if
(
up
->
su_type
==
SU_PORT_KBD
)
up
->
cflag
=
B1200
|
CS8
|
CLOCAL
|
CREAD
;
else
up
->
cflag
=
B4800
|
CS8
|
CLOCAL
|
CREAD
;
if
(
up
->
su_type
==
SU_PORT_KBD
)
up
->
cflag
=
B1200
|
CS8
|
CLOCAL
|
CREAD
;
else
up
->
cflag
=
B4800
|
CS8
|
CLOCAL
|
CREAD
;
sunsu_autoconfig
(
up
);
if
(
up
->
port
.
type
==
PORT_UNKNOWN
)
continue
;
sunsu_autoconfig
(
up
);
if
(
up
->
port
.
type
==
PORT_UNKNOWN
)
return
-
1
;
printk
(
KERN_INFO
"su%d at 0x%p (irq = %s) is a %s
\n
"
,
i
,
up
->
port
.
membase
,
__irq_itoa
(
up
->
irq
),
sunsu_type
(
&
up
->
port
));
printk
(
KERN_INFO
"su%d at 0x%p (irq = %s) is a %s
\n
"
,
channel
,
up
->
port
.
membase
,
__irq_itoa
(
up
->
irq
),
sunsu_type
(
&
up
->
port
));
#ifdef CONFIG_SERIO
memset
(
&
up
->
serio
,
0
,
sizeof
(
up
->
serio
));
up
->
serio
=
serio
=
kmalloc
(
sizeof
(
struct
serio
),
GFP_KERNEL
);
if
(
serio
)
{
memset
(
serio
,
0
,
sizeof
(
serio
));
up
->
serio
.
driver
=
up
;
serio
->
port_data
=
up
;
up
->
serio
.
type
=
SERIO_RS232
;
serio
->
type
=
SERIO_RS232
;
if
(
up
->
su_type
==
SU_PORT_KBD
)
{
up
->
serio
.
type
|=
SERIO_SUNKBD
;
up
->
serio
.
name
=
"sukbd"
;
serio
->
type
|=
SERIO_SUNKBD
;
strlcpy
(
serio
->
name
,
"sukbd"
,
sizeof
(
serio
->
name
))
;
}
else
{
up
->
serio
.
type
|=
(
SERIO_SUN
|
(
1
<<
16
));
up
->
serio
.
name
=
"sums"
;
serio
->
type
|=
(
SERIO_SUN
|
(
1
<<
16
));
strlcpy
(
serio
->
name
,
"sums"
,
sizeof
(
serio
->
name
))
;
}
up
->
serio
.
phys
=
(
i
==
0
?
"su/serio0"
:
"su/serio1"
);
strlcpy
(
serio
->
phys
,
(
channel
==
0
?
"su/serio0"
:
"su/serio1"
),
sizeof
(
serio
->
phys
));
up
->
serio
.
write
=
sunsu_serio_write
;
up
->
serio
.
open
=
sunsu_serio_open
;
up
->
serio
.
close
=
sunsu_serio_close
;
serio
->
write
=
sunsu_serio_write
;
serio
->
open
=
sunsu_serio_open
;
serio
->
close
=
sunsu_serio_close
;
serio_register_port
(
&
up
->
serio
);
serio_register_port
(
serio
);
}
else
{
printk
(
KERN_WARNING
"su%d: not enough memory for serio port
\n
"
,
channel
);
}
#endif
sunsu_startup
(
&
up
->
port
);
}
sunsu_startup
(
&
up
->
port
);
return
0
;
}
...
...
@@ -1680,10 +1684,12 @@ static int __init sunsu_probe(void)
if
(
scan
.
msx
!=
-
1
&&
scan
.
kbx
!=
-
1
)
{
sunsu_ports
[
0
].
su_type
=
SU_PORT_MS
;
sunsu_ports
[
0
].
port_node
=
scan
.
msnode
;
sunsu_kbd_ms_init
(
&
sunsu_ports
[
0
],
0
);
sunsu_ports
[
1
].
su_type
=
SU_PORT_KBD
;
sunsu_ports
[
1
].
port_node
=
scan
.
kbnode
;
sunsu_kbd_ms_init
(
&
sunsu_ports
[
1
],
1
);
sunsu_kbd_ms_init
();
return
0
;
}
...
...
@@ -1715,7 +1721,10 @@ static void __exit sunsu_exit(void)
if
(
up
->
su_type
==
SU_PORT_MS
||
up
->
su_type
==
SU_PORT_KBD
)
{
#ifdef CONFIG_SERIO
serio_unregister_port
(
&
up
->
serio
);
if
(
up
->
serio
)
{
serio_unregister_port
(
up
->
serio
);
up
->
serio
=
NULL
;
}
#endif
}
else
if
(
up
->
port
.
type
!=
PORT_UNKNOWN
)
{
uart_remove_one_port
(
&
sunsu_reg
,
&
up
->
port
);
...
...
drivers/serial/sunzilog.c
View file @
73df7566
...
...
@@ -107,7 +107,7 @@ struct uart_sunzilog_port {
unsigned
char
prev_status
;
#ifdef CONFIG_SERIO
struct
serio
serio
;
struct
serio
*
serio
;
int
serio_open
;
#endif
};
...
...
@@ -291,7 +291,7 @@ static void sunzilog_kbdms_receive_chars(struct uart_sunzilog_port *up,
/* Stop-A is handled by drivers/char/keyboard.c now. */
#ifdef CONFIG_SERIO
if
(
up
->
serio_open
)
serio_interrupt
(
&
up
->
serio
,
ch
,
0
,
regs
);
serio_interrupt
(
up
->
serio
,
ch
,
0
,
regs
);
#endif
}
else
if
(
ZS_IS_MOUSE
(
up
))
{
int
ret
=
suncore_mouse_baud_detection
(
ch
,
is_break
);
...
...
@@ -306,7 +306,7 @@ static void sunzilog_kbdms_receive_chars(struct uart_sunzilog_port *up,
case
0
:
#ifdef CONFIG_SERIO
if
(
up
->
serio_open
)
serio_interrupt
(
&
up
->
serio
,
ch
,
0
,
regs
);
serio_interrupt
(
up
->
serio
,
ch
,
0
,
regs
);
#endif
break
;
};
...
...
@@ -1295,7 +1295,7 @@ static spinlock_t sunzilog_serio_lock = SPIN_LOCK_UNLOCKED;
static
int
sunzilog_serio_write
(
struct
serio
*
serio
,
unsigned
char
ch
)
{
struct
uart_sunzilog_port
*
up
=
serio
->
driver
;
struct
uart_sunzilog_port
*
up
=
serio
->
port_data
;
unsigned
long
flags
;
spin_lock_irqsave
(
&
sunzilog_serio_lock
,
flags
);
...
...
@@ -1309,7 +1309,7 @@ static int sunzilog_serio_write(struct serio *serio, unsigned char ch)
static
int
sunzilog_serio_open
(
struct
serio
*
serio
)
{
struct
uart_sunzilog_port
*
up
=
serio
->
driver
;
struct
uart_sunzilog_port
*
up
=
serio
->
port_data
;
unsigned
long
flags
;
int
ret
;
...
...
@@ -1326,7 +1326,7 @@ static int sunzilog_serio_open(struct serio *serio)
static
void
sunzilog_serio_close
(
struct
serio
*
serio
)
{
struct
uart_sunzilog_port
*
up
=
serio
->
driver
;
struct
uart_sunzilog_port
*
up
=
serio
->
port_data
;
unsigned
long
flags
;
spin_lock_irqsave
(
&
sunzilog_serio_lock
,
flags
);
...
...
@@ -1545,33 +1545,45 @@ static void __init sunzilog_init_kbdms(struct uart_sunzilog_port *up, int channe
up
->
curregs
[
R15
]
=
BRKIE
;
brg
=
BPS_TO_BRG
(
baud
,
ZS_CLOCK
/
ZS_CLOCK_DIVISOR
);
sunzilog_convert_to_zs
(
up
,
up
->
cflag
,
0
,
brg
);
sunzilog_set_mctrl
(
&
up
->
port
,
TIOCM_DTR
|
TIOCM_RTS
);
__sunzilog_startup
(
up
);
}
#ifdef CONFIG_SERIO
memset
(
&
up
->
serio
,
0
,
sizeof
(
up
->
serio
));
static
void
__init
sunzilog_register_serio
(
struct
uart_sunzilog_port
*
up
,
int
channel
)
{
struct
serio
*
serio
;
up
->
serio
.
driver
=
up
;
up
->
serio
=
serio
=
kmalloc
(
sizeof
(
struct
serio
),
GFP_KERNEL
);
if
(
serio
)
{
up
->
serio
.
type
=
SERIO_RS232
;
if
(
channel
==
KEYBOARD_LINE
)
{
up
->
serio
.
type
|=
SERIO_SUNKBD
;
up
->
serio
.
name
=
"zskbd"
;
}
else
{
up
->
serio
.
type
|=
(
SERIO_SUN
|
(
1
<<
16
));
up
->
serio
.
name
=
"zsms"
;
}
up
->
serio
.
phys
=
(
channel
==
KEYBOARD_LINE
?
"zs/serio0"
:
"zs/serio1"
);
memset
(
serio
,
0
,
sizeof
(
serio
));
up
->
serio
.
write
=
sunzilog_serio_write
;
up
->
serio
.
open
=
sunzilog_serio_open
;
up
->
serio
.
close
=
sunzilog_serio_close
;
serio
->
port_data
=
up
;
serio_register_port
(
&
up
->
serio
);
#endif
serio
->
type
=
SERIO_RS232
;
if
(
channel
==
KEYBOARD_LINE
)
{
serio
->
type
|=
SERIO_SUNKBD
;
strlcpy
(
serio
->
name
,
"zskbd"
,
sizeof
(
serio
->
name
));
}
else
{
serio
->
type
|=
(
SERIO_SUN
|
(
1
<<
16
));
strlcpy
(
serio
->
name
,
"zsms"
,
sizeof
(
serio
->
name
));
}
strlcpy
(
serio
->
phys
,
(
channel
==
KEYBOARD_LINE
?
"zs/serio0"
:
"zs/serio1"
),
sizeof
(
serio
->
phys
));
sunzilog_set_mctrl
(
&
up
->
port
,
TIOCM_DTR
|
TIOCM_RTS
);
__sunzilog_startup
(
up
);
serio
->
write
=
sunzilog_serio_write
;
serio
->
open
=
sunzilog_serio_open
;
serio
->
close
=
sunzilog_serio_close
;
serio_register_port
(
serio
);
}
else
{
printk
(
KERN_WARNING
"zs%d: not enough memory for serio port
\n
"
,
channel
);
}
}
#endif
static
void
__init
sunzilog_init_hw
(
void
)
{
...
...
@@ -1615,6 +1627,11 @@ static void __init sunzilog_init_hw(void)
}
spin_unlock_irqrestore
(
&
up
->
port
.
lock
,
flags
);
#ifdef CONFIG_SERIO
if
(
i
==
KEYBOARD_LINE
||
i
==
MOUSE_LINE
)
sunzilog_register_serio
(
up
,
i
);
#endif
}
}
...
...
@@ -1732,10 +1749,15 @@ static void __exit sunzilog_exit(void)
for
(
i
=
0
;
i
<
NUM_CHANNELS
;
i
++
)
{
struct
uart_sunzilog_port
*
up
=
&
sunzilog_port_table
[
i
];
if
(
ZS_IS_KEYB
(
up
)
||
ZS_IS_MOUSE
(
up
))
continue
;
uart_remove_one_port
(
&
sunzilog_reg
,
&
up
->
port
);
if
(
ZS_IS_KEYB
(
up
)
||
ZS_IS_MOUSE
(
up
))
{
#ifdef CONFIG_SERIO
if
(
up
->
serio
)
{
serio_unregister_port
(
up
->
serio
);
up
->
serio
=
NULL
;
}
#endif
}
else
uart_remove_one_port
(
&
sunzilog_reg
,
&
up
->
port
);
}
uart_unregister_driver
(
&
sunzilog_reg
);
...
...
drivers/usb/input/hid-core.c
View file @
73df7566
...
...
@@ -1439,6 +1439,11 @@ void hid_init_reports(struct hid_device *hid)
#define USB_DEVICE_ID_1_PHIDGETSERVO_20 0x8101
#define USB_DEVICE_ID_4_PHIDGETSERVO_20 0x8104
#define USB_VENDOR_ID_CODEMERCS 0x07c0
#define USB_DEVICE_ID_CODEMERCS_IOW40 0x1500
#define USB_DEVICE_ID_CODEMERCS_IOW24 0x1501
static
struct
hid_blacklist
{
__u16
idVendor
;
__u16
idProduct
;
...
...
@@ -1453,20 +1458,20 @@ static struct hid_blacklist {
{
USB_VENDOR_ID_AIPTEK
,
USB_DEVICE_ID_AIPTEK_23
,
HID_QUIRK_IGNORE
},
{
USB_VENDOR_ID_AIPTEK
,
USB_DEVICE_ID_AIPTEK_24
,
HID_QUIRK_IGNORE
},
{
USB_VENDOR_ID_BERKSHIRE
,
USB_DEVICE_ID_BERKSHIRE_PCWD
,
HID_QUIRK_IGNORE
},
{
USB_VENDOR_ID_CODEMERCS
,
USB_DEVICE_ID_CODEMERCS_IOW40
,
HID_QUIRK_IGNORE
},
{
USB_VENDOR_ID_CODEMERCS
,
USB_DEVICE_ID_CODEMERCS_IOW24
,
HID_QUIRK_IGNORE
},
{
USB_VENDOR_ID_ESSENTIAL_REALITY
,
USB_DEVICE_ID_ESSENTIAL_REALITY_P5
,
HID_QUIRK_IGNORE
},
{
USB_VENDOR_ID_KBGEAR
,
USB_DEVICE_ID_KBGEAR_JAMSTUDIO
,
HID_QUIRK_IGNORE
},
{
USB_VENDOR_ID_GRIFFIN
,
USB_DEVICE_ID_POWERMATE
,
HID_QUIRK_IGNORE
},
{
USB_VENDOR_ID_GRIFFIN
,
USB_DEVICE_ID_SOUNDKNOB
,
HID_QUIRK_IGNORE
},
{
USB_VENDOR_ID_MGE
,
USB_DEVICE_ID_MGE_UPS
,
HID_QUIRK_IGNORE
},
{
USB_VENDOR_ID_MGE
,
USB_DEVICE_ID_MGE_UPS1
,
HID_QUIRK_IGNORE
},
{
USB_VENDOR_ID_ONTRAK
,
USB_DEVICE_ID_ONTRAK_ADU100
,
HID_QUIRK_IGNORE
},
{
USB_VENDOR_ID_ONTRAK
,
USB_DEVICE_ID_ONTRAK_ADU100
+
100
,
HID_QUIRK_IGNORE
},
{
USB_VENDOR_ID_ONTRAK
,
USB_DEVICE_ID_ONTRAK_ADU100
+
200
,
HID_QUIRK_IGNORE
},
{
USB_VENDOR_ID_ONTRAK
,
USB_DEVICE_ID_ONTRAK_ADU100
+
300
,
HID_QUIRK_IGNORE
},
{
USB_VENDOR_ID_ONTRAK
,
USB_DEVICE_ID_ONTRAK_ADU100
+
400
,
HID_QUIRK_IGNORE
},
{
USB_VENDOR_ID_ONTRAK
,
USB_DEVICE_ID_ONTRAK_ADU100
+
500
,
HID_QUIRK_IGNORE
},
{
USB_VENDOR_ID_WACOM
,
USB_DEVICE_ID_WACOM_PENPARTNER
,
HID_QUIRK_IGNORE
},
{
USB_VENDOR_ID_WACOM
,
USB_DEVICE_ID_WACOM_GRAPHIRE
,
HID_QUIRK_IGNORE
},
{
USB_VENDOR_ID_WACOM
,
USB_DEVICE_ID_WACOM_GRAPHIRE
+
1
,
HID_QUIRK_IGNORE
},
...
...
drivers/usb/input/hiddev.c
View file @
73df7566
...
...
@@ -223,16 +223,6 @@ static int hiddev_fasync(int fd, struct file *file, int on)
return
retval
<
0
?
retval
:
0
;
}
/*
* De-allocate a hiddev structure
*/
static
struct
usb_class_driver
hiddev_class
;
static
void
hiddev_cleanup
(
struct
hiddev
*
hiddev
)
{
hiddev_table
[
hiddev
->
hid
->
minor
-
HIDDEV_MINOR_BASE
]
=
NULL
;
usb_deregister_dev
(
hiddev
->
hid
->
intf
,
&
hiddev_class
);
kfree
(
hiddev
);
}
/*
* release file op
...
...
@@ -253,7 +243,7 @@ static int hiddev_release(struct inode * inode, struct file * file)
if
(
list
->
hiddev
->
exist
)
hid_close
(
list
->
hiddev
->
hid
);
else
hiddev_cleanup
(
list
->
hiddev
);
kfree
(
list
->
hiddev
);
}
kfree
(
list
);
...
...
@@ -636,16 +626,19 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
goto
inval
;
field
=
report
->
field
[
uref
->
field_index
];
if
(
uref
->
usage_index
>=
field
->
maxusage
)
goto
inval
;
if
(
cmd
==
HIDIOCGUSAGES
||
cmd
==
HIDIOCSUSAGES
)
{
if
(
uref_multi
->
num_values
>=
HID_MAX_USAGES
||
uref
->
usage_index
>=
field
->
maxusage
||
(
uref
->
usage_index
+
uref_multi
->
num_values
)
>=
field
->
maxusage
)
if
(
cmd
==
HIDIOCGCOLLECTIONINDEX
)
{
if
(
uref
->
usage_index
>=
field
->
maxusage
)
goto
inval
;
}
else
if
(
uref
->
usage_index
>=
field
->
report_count
)
goto
inval
;
else
if
((
cmd
==
HIDIOCGUSAGES
||
cmd
==
HIDIOCSUSAGES
)
&&
(
uref_multi
->
num_values
>=
HID_MAX_MULTI_USAGES
||
uref
->
usage_index
+
uref_multi
->
num_values
>=
field
->
report_count
||
uref
->
usage_index
+
uref_multi
->
num_values
<
uref
->
usage_index
))
goto
inval
;
}
}
switch
(
cmd
)
{
case
HIDIOCGUSAGE
:
...
...
@@ -795,17 +788,21 @@ int hiddev_connect(struct hid_device *hid)
* This is where hid.c calls us to disconnect a hiddev device from the
* corresponding hid device (usually because the usb device has disconnected)
*/
static
struct
usb_class_driver
hiddev_class
;
void
hiddev_disconnect
(
struct
hid_device
*
hid
)
{
struct
hiddev
*
hiddev
=
hid
->
hiddev
;
hiddev
->
exist
=
0
;
hiddev_table
[
hiddev
->
hid
->
minor
-
HIDDEV_MINOR_BASE
]
=
NULL
;
usb_deregister_dev
(
hiddev
->
hid
->
intf
,
&
hiddev_class
);
if
(
hiddev
->
open
)
{
hid_close
(
hiddev
->
hid
);
wake_up_interruptible
(
&
hiddev
->
wait
);
}
else
{
hiddev_cleanup
(
hiddev
);
kfree
(
hiddev
);
}
}
...
...
fs/compat_ioctl.c
View file @
73df7566
...
...
@@ -115,6 +115,8 @@
#include <linux/filter.h>
#include <linux/msdos_fs.h>
#include <linux/hiddev.h>
#undef INCLUDES
#endif
...
...
include/asm-ppc/8253pit.h
0 → 100644
View file @
73df7566
/*
* 8253/8254 Programmable Interval Timer
*/
#ifndef _8253PIT_H
#define _8253PIT_H
#define PIT_TICK_RATE 1193182UL
#endif
include/asm-ppc64/8253pit.h
0 → 100644
View file @
73df7566
/*
* 8253/8254 Programmable Interval Timer
*/
#ifndef _8253PIT_H
#define _8253PIT_H
#define PIT_TICK_RATE 1193182UL
#endif
include/linux/compat_ioctl.h
View file @
73df7566
...
...
@@ -732,3 +732,20 @@ COMPATIBLE_IOCTL(SIOCSIWRETRY)
COMPATIBLE_IOCTL
(
SIOCGIWRETRY
)
COMPATIBLE_IOCTL
(
SIOCSIWPOWER
)
COMPATIBLE_IOCTL
(
SIOCGIWPOWER
)
/* hiddev */
COMPATIBLE_IOCTL
(
HIDIOCGVERSION
)
COMPATIBLE_IOCTL
(
HIDIOCAPPLICATION
)
COMPATIBLE_IOCTL
(
HIDIOCGDEVINFO
)
COMPATIBLE_IOCTL
(
HIDIOCGSTRING
)
COMPATIBLE_IOCTL
(
HIDIOCINITREPORT
)
COMPATIBLE_IOCTL
(
HIDIOCGREPORT
)
COMPATIBLE_IOCTL
(
HIDIOCSREPORT
)
COMPATIBLE_IOCTL
(
HIDIOCGREPORTINFO
)
COMPATIBLE_IOCTL
(
HIDIOCGFIELDINFO
)
COMPATIBLE_IOCTL
(
HIDIOCGUSAGE
)
COMPATIBLE_IOCTL
(
HIDIOCSUSAGE
)
COMPATIBLE_IOCTL
(
HIDIOCGUCODE
)
COMPATIBLE_IOCTL
(
HIDIOCGFLAG
)
COMPATIBLE_IOCTL
(
HIDIOCSFLAG
)
COMPATIBLE_IOCTL
(
HIDIOCGCOLLECTIONINDEX
)
COMPATIBLE_IOCTL
(
HIDIOCGCOLLECTIONINFO
)
include/linux/hiddev.h
View file @
73df7566
...
...
@@ -128,10 +128,11 @@ struct hiddev_usage_ref {
/* hiddev_usage_ref_multi is used for sending multiple bytes to a control.
* It really manifests itself as setting the value of consecutive usages */
#define HID_MAX_MULTI_USAGES 1024
struct
hiddev_usage_ref_multi
{
struct
hiddev_usage_ref
uref
;
__u32
num_values
;
__s32
values
[
HID_MAX_USAGES
];
__s32
values
[
HID_MAX_
MULTI_
USAGES
];
};
/* FIELD_INDEX_NONE is returned in read() data from the kernel when flags
...
...
@@ -212,6 +213,11 @@ struct hiddev_usage_ref_multi {
* In-kernel definitions.
*/
struct
hid_device
;
struct
hid_usage
;
struct
hid_field
;
struct
hid_report
;
#ifdef CONFIG_USB_HIDDEV
int
hiddev_connect
(
struct
hid_device
*
);
void
hiddev_disconnect
(
struct
hid_device
*
);
...
...
include/linux/input.h
View file @
73df7566
...
...
@@ -527,6 +527,8 @@ struct input_absinfo {
#define MSC_SERIAL 0x00
#define MSC_PULSELED 0x01
#define MSC_GESTURE 0x02
#define MSC_RAW 0x03
#define MSC_SCAN 0x04
#define MSC_MAX 0x07
/*
...
...
include/linux/serio.h
View file @
73df7566
...
...
@@ -17,12 +17,17 @@
#ifdef __KERNEL__
#include <linux/list.h>
#include <linux/spinlock.h>
#include <linux/device.h>
struct
serio
{
void
*
private
;
void
*
driver
;
char
*
name
;
char
*
phys
;
void
*
port_data
;
char
name
[
32
];
char
phys
[
32
];
unsigned
int
manual_bind
;
unsigned
short
idbus
;
unsigned
short
idvendor
;
...
...
@@ -32,31 +37,43 @@ struct serio {
unsigned
long
type
;
unsigned
long
event
;
spinlock_t
lock
;
/* protects critical sections from port's interrupt handler */
int
(
*
write
)(
struct
serio
*
,
unsigned
char
);
int
(
*
open
)(
struct
serio
*
);
void
(
*
close
)(
struct
serio
*
);
struct
serio_dev
*
dev
;
struct
serio
*
parent
,
*
child
;
struct
serio_driver
*
drv
;
/* accessed from interrupt, must be protected by serio->lock */
struct
device
dev
;
struct
list_head
node
;
};
#define to_serio_port(d) container_of(d, struct serio, dev)
struct
serio_d
ev
{
struct
serio_d
river
{
void
*
private
;
char
*
name
;
char
*
description
;
unsigned
int
manual_bind
;
void
(
*
write_wakeup
)(
struct
serio
*
);
irqreturn_t
(
*
interrupt
)(
struct
serio
*
,
unsigned
char
,
unsigned
int
,
struct
pt_regs
*
);
void
(
*
connect
)(
struct
serio
*
,
struct
serio_d
ev
*
de
v
);
void
(
*
connect
)(
struct
serio
*
,
struct
serio_d
river
*
dr
v
);
int
(
*
reconnect
)(
struct
serio
*
);
void
(
*
disconnect
)(
struct
serio
*
);
void
(
*
cleanup
)(
struct
serio
*
);
struct
device_driver
driver
;
struct
list_head
node
;
};
#define to_serio_driver(d) container_of(d, struct serio_driver, driver)
int
serio_open
(
struct
serio
*
serio
,
struct
serio_d
ev
*
de
v
);
int
serio_open
(
struct
serio
*
serio
,
struct
serio_d
river
*
dr
v
);
void
serio_close
(
struct
serio
*
serio
);
void
serio_rescan
(
struct
serio
*
serio
);
void
serio_reconnect
(
struct
serio
*
serio
);
...
...
@@ -64,12 +81,11 @@ irqreturn_t serio_interrupt(struct serio *serio, unsigned char data, unsigned in
void
serio_register_port
(
struct
serio
*
serio
);
void
serio_register_port_delayed
(
struct
serio
*
serio
);
void
__serio_register_port
(
struct
serio
*
serio
);
void
serio_unregister_port
(
struct
serio
*
serio
);
void
serio_unregister_port_delayed
(
struct
serio
*
serio
);
void
__serio_unregister_port
(
struct
serio
*
serio
);
void
serio_register_d
evice
(
struct
serio_dev
*
de
v
);
void
serio_unregister_d
evice
(
struct
serio_dev
*
de
v
);
void
serio_register_d
river
(
struct
serio_driver
*
dr
v
);
void
serio_unregister_d
river
(
struct
serio_driver
*
dr
v
);
static
__inline__
int
serio_write
(
struct
serio
*
serio
,
unsigned
char
data
)
{
...
...
@@ -79,18 +95,34 @@ static __inline__ int serio_write(struct serio *serio, unsigned char data)
return
-
1
;
}
static
__inline__
void
serio_d
e
v_write_wakeup
(
struct
serio
*
serio
)
static
__inline__
void
serio_d
r
v_write_wakeup
(
struct
serio
*
serio
)
{
if
(
serio
->
d
ev
&&
serio
->
de
v
->
write_wakeup
)
serio
->
d
e
v
->
write_wakeup
(
serio
);
if
(
serio
->
d
rv
&&
serio
->
dr
v
->
write_wakeup
)
serio
->
d
r
v
->
write_wakeup
(
serio
);
}
static
__inline__
void
serio_cleanup
(
struct
serio
*
serio
)
{
if
(
serio
->
dev
&&
serio
->
dev
->
cleanup
)
serio
->
dev
->
cleanup
(
serio
);
if
(
serio
->
drv
&&
serio
->
drv
->
cleanup
)
serio
->
drv
->
cleanup
(
serio
);
}
/*
* Use the following fucntions to protect critical sections in
* driver code from port's interrupt handler
*/
static
__inline__
void
serio_pause_rx
(
struct
serio
*
serio
)
{
spin_lock_irq
(
&
serio
->
lock
);
}
static
__inline__
void
serio_continue_rx
(
struct
serio
*
serio
)
{
spin_unlock_irq
(
&
serio
->
lock
);
}
#endif
/*
...
...
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