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
c5ec0513
Commit
c5ec0513
authored
Jul 29, 2004
by
Vojtech Pavlik
Browse files
Options
Browse Files
Download
Plain Diff
Merge
bk://dtor.bkbits.net/input
into suse.cz:/data/bk/input
parents
8b2910fd
419bd06b
Changes
16
Show whitespace changes
Inline
Side-by-side
Showing
16 changed files
with
620 additions
and
290 deletions
+620
-290
drivers/Makefile
drivers/Makefile
+3
-1
drivers/input/joydev.c
drivers/input/joydev.c
+4
-2
drivers/input/keyboard/atkbd.c
drivers/input/keyboard/atkbd.c
+130
-48
drivers/input/mouse/psmouse-base.c
drivers/input/mouse/psmouse-base.c
+145
-87
drivers/input/mouse/psmouse.h
drivers/input/mouse/psmouse.h
+14
-8
drivers/input/mouse/synaptics.c
drivers/input/mouse/synaptics.c
+12
-14
drivers/input/mousedev.c
drivers/input/mousedev.c
+41
-10
drivers/input/serio/ct82c710.c
drivers/input/serio/ct82c710.c
+28
-22
drivers/input/serio/i8042.c
drivers/input/serio/i8042.c
+76
-44
drivers/input/serio/maceps2.c
drivers/input/serio/maceps2.c
+14
-5
drivers/input/serio/q40kbd.c
drivers/input/serio/q40kbd.c
+14
-4
drivers/input/serio/rpckbd.c
drivers/input/serio/rpckbd.c
+15
-5
drivers/input/serio/serio.c
drivers/input/serio/serio.c
+84
-27
drivers/input/tsdev.c
drivers/input/tsdev.c
+5
-5
drivers/serial/sunzilog.c
drivers/serial/sunzilog.c
+13
-5
include/linux/serio.h
include/linux/serio.h
+22
-3
No files found.
drivers/Makefile
View file @
c5ec0513
...
...
@@ -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/
...
...
@@ -37,7 +40,6 @@ obj-$(CONFIG_PARIDE) += block/paride/
obj-$(CONFIG_TC)
+=
tc/
obj-$(CONFIG_USB)
+=
usb/
obj-$(CONFIG_USB_GADGET)
+=
usb/gadget/
obj-$(CONFIG_SERIO)
+=
input/serio/
obj-$(CONFIG_INPUT)
+=
input/
obj-$(CONFIG_GAMEPORT)
+=
input/gameport/
obj-$(CONFIG_I2O)
+=
message/
...
...
drivers/input/joydev.c
View file @
c5ec0513
...
...
@@ -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/keyboard/atkbd.c
View file @
c5ec0513
...
...
@@ -173,8 +173,7 @@ static unsigned char atkbd_scroll_keys[5][2] = {
#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_ID 3
/* First byte is not keyboard ID */
#define ATKBD_FLAG_ENABLED 4
/* Waining for init to finish */
#define ATKBD_FLAG_ENABLED 3
/* Waining for init to finish */
/*
* The atkbd control structure
...
...
@@ -210,10 +209,25 @@ struct atkbd {
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
);
...
...
@@ -254,37 +268,38 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
atkbd
->
resend
=
0
;
#endif
if
(
test_bit
(
ATKBD_FLAG_ACK
,
&
atkbd
->
flags
))
if
(
test_bit
(
ATKBD_FLAG_ACK
,
&
atkbd
->
flags
))
{
switch
(
code
)
{
case
ATKBD_RET_ACK
:
atkbd
->
nak
=
0
;
if
(
atkbd
->
cmdcnt
)
{
set_bit
(
ATKBD_FLAG_CMD
,
&
atkbd
->
flags
);
set_bit
(
ATKBD_FLAG_CMD1
,
&
atkbd
->
flags
);
set_bit
(
ATKBD_FLAG_ID
,
&
atkbd
->
flags
);
}
clear_bit
(
ATKBD_FLAG_ACK
,
&
atkbd
->
flags
);
goto
out
;
wake_up_interruptible
(
&
atkbd
->
wait
);
break
;
case
ATKBD_RET_NAK
:
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
))
{
atkbd
->
cmdcnt
--
;
atkbd
->
cmdbuf
[
atkbd
->
cmdcnt
]
=
code
;
if
(
atkbd
->
cmdcnt
)
atkbd
->
cmdbuf
[
--
atkbd
->
cmdcnt
]
=
code
;
if
(
atkbd
->
cmdcnt
==
1
)
{
if
(
code
!=
0xab
&&
code
!=
0xac
)
clear_bit
(
ATKBD_FLAG_ID
,
&
atkbd
->
flags
);
clear_bit
(
ATKBD_FLAG_CMD1
,
&
atkbd
->
flags
);
}
if
(
test_and_clear_bit
(
ATKBD_FLAG_CMD1
,
&
atkbd
->
flags
)
&&
atkbd
->
cmdcnt
)
wake_up_interruptible
(
&
atkbd
->
wait
);
if
(
!
atkbd
->
cmdcnt
)
if
(
!
atkbd
->
cmdcnt
)
{
clear_bit
(
ATKBD_FLAG_CMD
,
&
atkbd
->
flags
);
wake_up_interruptible
(
&
atkbd
->
wait
);
}
goto
out
;
}
...
...
@@ -417,87 +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
=
200000
;
/* 200 msec */
#ifdef ATKBD_DEBUG
printk
(
KERN_DEBUG
"atkbd.c: Sent: %02x
\n
"
,
byte
);
#endif
atkbd
->
nak
=
1
;
set_bit
(
ATKBD_FLAG_ACK
,
&
atkbd
->
flags
);
clear_bit
(
ATKBD_FLAG_CMD
,
&
atkbd
->
flags
);
if
(
serio_write
(
atkbd
->
serio
,
byte
))
return
-
1
;
while
(
test_bit
(
ATKBD_FLAG_ACK
,
&
atkbd
->
flags
)
&&
timeout
--
)
udelay
(
1
);
clear_bit
(
ATKBD_FLAG_ACK
,
&
atkbd
->
flags
);
if
(
serio_write
(
atkbd
->
serio
,
byte
)
==
0
)
wait_event_interruptible_timeout
(
atkbd
->
wait
,
!
test_bit
(
ATKBD_FLAG_ACK
,
&
atkbd
->
flags
),
msecs_to_jiffies
(
200
));
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
=
4000000
;
/* 4 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
-
1
;
goto
out
;
for
(
i
=
0
;
i
<
send
;
i
++
)
if
(
atkbd_sendbyte
(
atkbd
,
param
[
i
]))
return
-
1
;
while
(
test_bit
(
ATKBD_FLAG_CMD
,
&
atkbd
->
flags
)
&&
timeout
--
)
{
goto
out
;
if
(
!
test_bit
(
ATKBD_FLAG_CMD1
,
&
atkbd
->
flags
))
{
timeout
=
wait_event_interruptible_timeout
(
atkbd
->
wait
,
!
test_bit
(
ATKBD_FLAG_CMD1
,
&
atkbd
->
flags
),
timeout
);
if
(
command
==
ATKBD_CMD_RESET_BAT
&&
timeout
>
100000
)
timeout
=
100000
;
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
&&
!
test_bit
(
ATKBD_FLAG_ID
,
&
atkbd
->
flags
))
{
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
);
}
clear_bit
(
ATKBD_FLAG_CMD
,
&
atkbd
->
flags
);
if
(
param
)
for
(
i
=
0
;
i
<
receive
;
i
++
)
param
[
i
]
=
atkbd
->
cmdbuf
[(
receive
-
1
)
-
i
];
if
(
command
==
ATKBD_CMD_RESET_BAT
&&
atkbd
->
cmdcnt
==
1
)
return
0
;
if
(
atkbd
->
cmdcnt
&&
(
command
!=
ATKBD_CMD_RESET_BAT
||
atkbd
->
cmdcnt
!=
1
)
)
goto
out
;
if
(
atkbd
->
cmdcnt
)
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
(
!
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.
...
...
@@ -524,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
;
...
...
@@ -533,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
;
...
...
@@ -549,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
;
}
...
...
@@ -721,7 +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
);
...
...
@@ -743,6 +822,9 @@ static void atkbd_connect(struct serio *serio, struct serio_driver *drv)
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
:
...
...
drivers/input/mouse/psmouse-base.c
View file @
c5ec0513
...
...
@@ -147,45 +147,64 @@ static irqreturn_t psmouse_interrupt(struct serio *serio,
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
(
test_bit
(
PSMOUSE_FLAG_ACK
,
&
psmouse
->
flags
))
if
(
test_bit
(
PSMOUSE_FLAG_ACK
,
&
psmouse
->
flags
))
{
switch
(
data
)
{
case
PSMOUSE_RET_ACK
:
psmouse
->
nak
=
0
;
clear_bit
(
PSMOUSE_FLAG_ACK
,
&
psmouse
->
flags
);
goto
out
;
break
;
case
PSMOUSE_RET_NAK
:
psmouse
->
nak
=
1
;
clear_bit
(
PSMOUSE_FLAG_ACK
,
&
psmouse
->
flags
);
goto
out
;
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
->
nak
=
0
;
/* Workaround for mice which don't ACK the Get ID command */
clear_bit
(
PSMOUSE_FLAG_ACK
,
&
psmouse
->
flags
);
if
(
!
test_bit
(
PSMOUSE_FLAG_CMD
,
&
psmouse
->
flags
))
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
(
test_bit
(
PSMOUSE_FLAG_CMD
,
&
psmouse
->
flags
))
{
if
(
data
==
PSMOUSE_RET_ACK
||
data
==
PSMOUSE_RET_NAK
)
goto
out
;
}
psmouse
->
cmdcnt
--
;
psmouse
->
cmdbuf
[
psmouse
->
cmdcnt
]
=
data
;
if
(
test_bit
(
PSMOUSE_FLAG_CMD
,
&
psmouse
->
flags
))
{
if
(
psmouse
->
cmdcnt
)
psmouse
->
cmdbuf
[
--
psmouse
->
cmdcnt
]
=
data
;
if
(
psmouse
->
cmdcnt
==
1
)
{
if
(
data
!=
0xab
&&
data
!=
0xac
)
clear_bit
(
PSMOUSE_FLAG_ID
,
&
psmouse
->
flags
);
clear_bit
(
PSMOUSE_FLAG_CMD1
,
&
psmouse
->
flags
);
}
if
(
test_and_clear_bit
(
PSMOUSE_FLAG_CMD1
,
&
psmouse
->
flags
)
&&
psmouse
->
cmdcnt
)
wake_up_interruptible
(
&
psmouse
->
wait
);
if
(
!
psmouse
->
cmdcnt
)
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
"
,
...
...
@@ -251,90 +270,95 @@ 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
=
200000
;
/* 200 msec */
psmouse
->
nak
=
1
;
set_bit
(
PSMOUSE_FLAG_ACK
,
&
psmouse
->
flags
);
if
(
serio_write
(
psmouse
->
serio
,
byte
))
return
-
1
;
while
(
test_bit
(
PSMOUSE_FLAG_ACK
,
&
psmouse
->
flags
)
&&
timeout
--
)
udelay
(
1
);
clear_bit
(
PSMOUSE_FLAG_ACK
,
&
psmouse
->
flags
);
if
(
serio_write
(
psmouse
->
serio
,
byte
)
==
0
)
wait_event_interruptible_timeout
(
psmouse
->
wait
,
!
test_bit
(
PSMOUSE_FLAG_ACK
,
&
psmouse
->
flags
),
msecs_to_jiffies
(
200
));
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
);
if
(
receive
&&
param
)
for
(
i
=
0
;
i
<
receive
;
i
++
)
psmouse
->
cmdbuf
[(
receive
-
1
)
-
i
]
=
param
[
i
];
if
(
receive
)
{
set_bit
(
PSMOUSE_FLAG_CMD
,
&
psmouse
->
flags
);
set_bit
(
PSMOUSE_FLAG_CMD1
,
&
psmouse
->
flags
);
set_bit
(
PSMOUSE_FLAG_ID
,
&
psmouse
->
flags
);
}
psmouse
->
cmdcnt
=
receive
;
if
(
command
&
0xff
)
if
(
psmouse_sendbyte
(
psmouse
,
command
&
0xff
))
{
clear_bit
(
PSMOUSE_FLAG_CMD
,
&
psmouse
->
flags
);
return
-
1
;
}
if
(
psmouse_sendbyte
(
psmouse
,
command
&
0xff
))
goto
out
;
for
(
i
=
0
;
i
<
send
;
i
++
)
if
(
psmouse_sendbyte
(
psmouse
,
param
[
i
]))
{
clear_bit
(
PSMOUSE_FLAG_CMD
,
&
psmouse
->
flags
);
return
-
1
;
}
while
(
test_bit
(
PSMOUSE_FLAG_CMD
,
&
psmouse
->
flags
)
&&
timeout
--
)
{
if
(
psmouse_sendbyte
(
psmouse
,
param
[
i
]))
goto
out
;
if
(
!
test_bit
(
PSMOUSE_FLAG_CMD1
,
&
psmouse
->
flags
))
{
timeout
=
wait_event_interruptible_timeout
(
psmouse
->
wait
,
!
test_bit
(
PSMOUSE_FLAG_CMD1
,
&
psmouse
->
flags
),
timeout
);
if
(
command
==
PSMOUSE_CMD_RESET_BAT
&&
timeout
>
100000
)
timeout
=
100000
;
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
&&
!
test_bit
(
PSMOUSE_FLAG_ID
,
&
psmouse
->
flags
))
{
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
);
}
clear_bit
(
PSMOUSE_FLAG_CMD
,
&
psmouse
->
flags
);
if
(
param
)
for
(
i
=
0
;
i
<
receive
;
i
++
)
param
[
i
]
=
psmouse
->
cmdbuf
[(
receive
-
1
)
-
i
];
if
(
command
==
PSMOUSE_CMD_RESET_BAT
&&
psmouse
->
cmdcnt
==
1
)
return
0
;
if
(
psmouse
->
cmdcnt
&&
(
command
!=
PSMOUSE_CMD_RESET_BAT
||
psmouse
->
cmdcnt
!=
1
)
)
goto
out
;
if
(
psmouse
->
cmdcnt
)
return
-
1
;
rc
=
0
;
return
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
;
}
/*
...
...
@@ -625,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.
*/
...
...
@@ -634,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.
*/
...
...
@@ -657,7 +711,7 @@ static void psmouse_disconnect(struct serio *serio)
struct
psmouse
*
psmouse
,
*
parent
;
psmouse
=
serio
->
private
;
psmouse
->
state
=
PSMOUSE_CMD_MODE
;
psmouse
_set_state
(
psmouse
,
PSMOUSE_CMD_MODE
)
;
if
(
serio
->
parent
&&
(
serio
->
type
&
SERIO_TYPE
)
==
SERIO_PS_PSTHRU
)
{
parent
=
serio
->
parent
->
private
;
...
...
@@ -668,7 +722,7 @@ static void psmouse_disconnect(struct serio *serio)
if
(
psmouse
->
disconnect
)
psmouse
->
disconnect
(
psmouse
);
psmouse
->
state
=
PSMOUSE_IGNORE
;
psmouse
_set_state
(
psmouse
,
PSMOUSE_IGNORE
)
;
input_unregister_device
(
&
psmouse
->
dev
);
serio_close
(
serio
);
...
...
@@ -687,21 +741,28 @@ static void psmouse_connect(struct serio *serio, struct serio_driver *drv)
(
serio
->
type
&
SERIO_TYPE
)
!=
SERIO_PS_PSTHRU
)
return
;
if
(
serio
->
parent
&&
(
serio
->
type
&
SERIO_TYPE
)
==
SERIO_PS_PSTHRU
)
/*
* 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
)))
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
,
drv
))
{
...
...
@@ -741,25 +802,21 @@ static void psmouse_connect(struct serio *serio, struct serio_driver *drv)
printk
(
KERN_INFO
"input: %s on %s
\n
"
,
psmouse
->
devname
,
serio
->
phys
);
psmouse_set_state
(
psmouse
,
PSMOUSE_CMD_MODE
);
psmouse_initialize
(
psmouse
);
if
(
parent
&&
parent
->
pt_activate
)
parent
->
pt_activate
(
parent
);
/*
* OK, the device is ready, we just need to activate it (turn the
* stream mode on). But if mouse has a pass-through port we don't
* want to do it yet to not disturb child detection.
* The child will activate this port when it's ready.
*/
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
);
}
else
}
psmouse_activate
(
psmouse
);
out:
...
...
@@ -774,45 +831,46 @@ static int psmouse_reconnect(struct serio *serio)
struct
psmouse
*
psmouse
=
serio
->
private
;
struct
psmouse
*
parent
=
NULL
;
struct
serio_driver
*
drv
=
serio
->
drv
;
int
rc
=
-
1
;
if
(
!
drv
||
!
psmouse
)
{
printk
(
KERN_DEBUG
"psmouse: reconnect request, but serio is disconnected, ignoring...
\n
"
);
return
-
1
;
}
psmouse
->
state
=
PSMOUSE_CMD_MODE
;
clear_bit
(
PSMOUSE_FLAG_ACK
,
&
psmouse
->
flags
);
clear_bit
(
PSMOUSE_FLAG_CMD
,
&
psmouse
->
flags
);
if
(
serio
->
parent
&&
(
serio
->
type
&
SERIO_TYPE
)
==
SERIO_PS_PSTHRU
)
{
parent
=
serio
->
parent
->
private
;
psmouse_deactivate
(
parent
);
}
psmouse
->
pktcnt
=
psmouse
->
out_of_sync
=
0
;
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_
initialize
(
psmouse
);
psmouse_
set_state
(
psmouse
,
PSMOUSE_CMD_MODE
);
if
(
serio
->
parent
&&
(
serio
->
type
&
SERIO_TYPE
)
==
SERIO_PS_PSTHRU
)
parent
=
serio
->
parent
->
private
;
psmouse_initialize
(
psmouse
);
if
(
parent
&&
parent
->
pt_activate
)
parent
->
pt_activate
(
parent
);
if
(
!
serio
->
child
)
psmouse_activate
(
psmouse
);
rc
=
0
;
out:
/* If this is a pass-through port the parent waits to be activated */
if
(
parent
)
psmouse_activate
(
parent
);
return
0
;
return
rc
;
}
...
...
drivers/input/mouse/psmouse.h
View file @
c5ec0513
...
...
@@ -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,15 +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
/* First byte of command response */
#define PSMOUSE_FLAG_ID 3
/* First byte is not keyboard ID */
#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
{
...
...
@@ -48,13 +51,16 @@ struct psmouse {
unsigned
char
model
;
unsigned
long
last
;
unsigned
long
out_of_sync
;
unsigned
char
state
;
enum
psmouse_state
state
;
unsigned
char
nak
;
char
error
;
char
devname
[
64
];
char
phys
[
32
];
unsigned
long
flags
;
/* 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
);
...
...
drivers/input/mouse/synaptics.c
View file @
c5ec0513
...
...
@@ -233,17 +233,14 @@ static void synaptics_pass_pt_packet(struct serio *ptport, unsigned char *packet
{
struct
psmouse
*
child
=
ptport
->
private
;
if
(
child
)
{
if
(
child
->
state
==
PSMOUSE_ACTIVATED
)
{
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
if
(
child
->
state
!=
PSMOUSE_IGNORE
)
{
}
else
serio_interrupt
(
ptport
,
packet
[
1
],
0
,
NULL
);
}
}
}
static
void
synaptics_pt_activate
(
struct
psmouse
*
psmouse
)
...
...
@@ -472,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
->
serio
->
child
&&
psmouse
->
serio
->
child
->
drv
&&
synaptics_is_pt_packet
(
psmouse
->
packet
))
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
}
else
synaptics_process_packet
(
psmouse
);
return
PSMOUSE_FULL_PACKET
;
...
...
drivers/input/mousedev.c
View file @
c5ec0513
...
...
@@ -52,8 +52,10 @@ 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_
motion
{
struct
mousedev_
hw_data
{
int
dx
,
dy
,
dz
;
int
x
,
y
;
int
abs_event
;
unsigned
long
buttons
;
};
...
...
@@ -66,7 +68,7 @@ struct mousedev {
struct
list_head
list
;
struct
input_handle
handle
;
struct
mousedev_
motion
packet
;
struct
mousedev_
hw_data
packet
;
unsigned
int
pkt_count
;
int
old_x
[
4
],
old_y
[
4
];
unsigned
long
touch
;
...
...
@@ -76,7 +78,12 @@ enum mousedev_emul {
MOUSEDEV_EMUL_PS2
,
MOUSEDEV_EMUL_IMPS
,
MOUSEDEV_EMUL_EXPS
}
__attribute__
((
packed
));
};
struct
mousedev_motion
{
int
dx
,
dy
,
dz
;
unsigned
long
buttons
;
};
#define PACKET_QUEUE_LEN 16
struct
mousedev_list
{
...
...
@@ -87,6 +94,7 @@ struct mousedev_list {
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
;
...
...
@@ -134,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
;
}
}
...
...
@@ -188,7 +200,7 @@ static void mousedev_key_event(struct mousedev *mousedev, unsigned int code, int
}
}
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
;
...
...
@@ -206,6 +218,18 @@ static void mousedev_notify_readers(struct mousedev *mousedev, struct mousedev_m
}
}
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
;
...
...
@@ -224,7 +248,7 @@ static void mousedev_touchpad_touch(struct mousedev *mousedev, int value)
{
if
(
!
value
)
{
if
(
mousedev
->
touch
&&
!
time_after
(
jiffies
,
mousedev
->
touch
+
msecs_to_jiffies
(
tap_time
)))
{
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
...
...
@@ -289,6 +313,7 @@ static void mousedev_event(struct input_handle *handle, unsigned int type, unsig
mousedev_notify_readers
(
&
mousedev_mix
,
&
mousedev
->
packet
);
mousedev
->
packet
.
dx
=
mousedev
->
packet
.
dy
=
mousedev
->
packet
.
dz
=
0
;
mousedev
->
packet
.
abs_event
=
0
;
}
break
;
}
...
...
@@ -374,6 +399,8 @@ static int mousedev_open(struct inode * inode, struct file * file)
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
;
...
...
@@ -524,11 +551,15 @@ 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
->
mousedev
->
exist
)
return
-
ENODEV
;
if
(
!
list
->
buffer
&&
list
->
ready
)
{
mousedev_packet
(
list
,
list
->
ps2
);
list
->
buffer
=
list
->
bufsiz
;
...
...
drivers/input/serio/ct82c710.c
View file @
c5ec0513
...
...
@@ -36,6 +36,7 @@
#include <linux/interrupt.h>
#include <linux/serio.h>
#include <linux/errno.h>
#include <linux/err.h>
#include <asm/io.h>
...
...
@@ -58,10 +59,12 @@ MODULE_LICENSE("GPL");
#define CT82C710_IRQ 12
static
struct
serio
*
ct82c710_port
;
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
...
...
@@ -70,7 +73,7 @@ static int ct82c710_status;
static
irqreturn_t
ct82c710_interrupt
(
int
cpl
,
void
*
dev_id
,
struct
pt_regs
*
regs
)
{
return
serio_interrupt
(
ct82c710_port
,
inb
(
ct82c710_data
),
0
,
regs
);
return
serio_interrupt
(
ct82c710_port
,
inb
(
CT82C710_DATA
),
0
,
regs
);
}
/*
...
...
@@ -81,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
--
;
...
...
@@ -98,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
"
);
...
...
@@ -113,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
;
}
...
...
@@ -142,7 +145,7 @@ 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
;
}
...
...
@@ -162,8 +165,9 @@ 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 */
...
...
@@ -181,8 +185,9 @@ static struct serio * __init ct82c710_allocate_port(void)
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%04
x/serio0"
,
ct82c710_data
);
snprintf
(
serio
->
phys
,
sizeof
(
serio
->
phys
),
"isa%04
lx/serio0"
,
CT82C710_DATA
);
}
return
serio
;
...
...
@@ -193,18 +198,19 @@ 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
);
if
(
!
(
ct82c710_port
=
ct82c710_allocate_port
()))
{
release_region
(
ct82c710_data
,
2
);
platform_device_unregister
(
ct82c710_device
);
return
-
ENOMEM
;
}
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
;
}
...
...
@@ -212,7 +218,7 @@ int __init ct82c710_init(void)
void
__exit
ct82c710_exit
(
void
)
{
serio_unregister_port
(
ct82c710_port
);
release_region
(
ct82c710_data
,
2
);
platform_device_unregister
(
ct82c710_device
);
}
module_init
(
ct82c710_init
);
...
...
drivers/input/serio/i8042.c
View file @
c5ec0513
...
...
@@ -21,6 +21,7 @@
#include <linux/sysdev.h>
#include <linux/pm.h>
#include <linux/serio.h>
#include <linux/err.h>
#include <asm/io.h>
...
...
@@ -100,9 +101,9 @@ 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
;
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
...
...
@@ -362,6 +363,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
);
...
...
@@ -378,44 +380,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
;
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
;
...
...
@@ -854,7 +879,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
,
...
...
@@ -864,25 +889,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"
),
static
void
i8042_shutdown
(
struct
device
*
dev
)
{
i8042_controller_cleanup
();
}
static
struct
device_driver
i8042_driver
=
{
.
name
=
"i8042"
,
.
bus
=
&
platform_bus_type
,
.
suspend
=
i8042_suspend
,
.
resume
=
i8042_resume
,
};
static
struct
sys_device
device_i8042
=
{
.
id
=
0
,
.
cls
=
&
kbc_sysclass
,
.
shutdown
=
i8042_shutdown
,
};
/*
...
...
@@ -913,6 +940,7 @@ static struct serio * __init i8042_allocate_kbd_port(void)
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
));
}
...
...
@@ -932,6 +960,7 @@ static struct serio * __init i8042_allocate_aux_port(void)
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
));
}
...
...
@@ -956,6 +985,7 @@ static struct serio * __init i8042_allocate_mux_port(int index)
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
);
}
...
...
@@ -966,6 +996,7 @@ static struct serio * __init i8042_allocate_mux_port(int index)
int
__init
i8042_init
(
void
)
{
int
i
;
int
err
;
dbg_init
();
...
...
@@ -981,6 +1012,16 @@ int __init i8042_init(void)
if
(
i8042_controller_init
())
return
-
ENODEV
;
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
<
I8042_NUM_MUX_PORTS
;
i
++
)
{
...
...
@@ -1001,13 +1042,6 @@ int __init i8042_init(void)
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
);
...
...
@@ -1024,11 +1058,6 @@ 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
)
...
...
@@ -1043,6 +1072,9 @@ void __exit i8042_exit(void)
del_timer_sync
(
&
i8042_timer
);
platform_device_unregister
(
i8042_platform_device
);
driver_unregister
(
&
i8042_driver
);
i8042_platform_exit
();
}
...
...
drivers/input/serio/maceps2.c
View file @
c5ec0513
...
...
@@ -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>
...
...
@@ -53,6 +54,7 @@ struct maceps2_data {
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
)
{
...
...
@@ -130,6 +132,7 @@ static struct serio * __init maceps2_allocate_port(int idx)
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
;
...
...
@@ -138,6 +141,10 @@ static struct serio * __init maceps2_allocate_port(int idx)
static
int
__init
maceps2_init
(
void
)
{
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
;
...
...
@@ -148,6 +155,7 @@ static int __init maceps2_init(void)
if
(
!
maceps2_port
[
0
]
||
!
maceps2_port
[
1
])
{
kfree
(
maceps2_port
[
0
]);
kfree
(
maceps2_port
[
1
]);
platform_device_unregister
(
maceps2_device
);
return
-
ENOMEM
;
}
...
...
@@ -161,6 +169,7 @@ static void __exit maceps2_exit(void)
{
serio_unregister_port
(
maceps2_port
[
0
]);
serio_unregister_port
(
maceps2_port
[
1
]);
platform_device_unregister
(
maceps2_device
);
}
module_init
(
maceps2_init
);
...
...
drivers/input/serio/q40kbd.c
View file @
c5ec0513
...
...
@@ -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>
...
...
@@ -49,6 +50,7 @@ MODULE_LICENSE("GPL");
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
)
{
...
...
@@ -123,6 +125,7 @@ static struct serio * __init q40kbd_allocate_port(void)
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
));
}
...
...
@@ -135,8 +138,14 @@ static int __init q40kbd_init(void)
if
(
!
MACH_IS_Q40
)
return
-
EIO
;
if
(
!
(
q40kbd_port
=
q40kbd_allocate_port
()))
q40kbd_device
=
platform_device_register_simple
(
"q40kbd"
,
-
1
,
NULL
,
0
);
if
(
IS_ERR
(
q40kbd_device
))
return
PTR_ERR
(
q40kbd_device
);
if
(
!
(
q40kbd_port
=
q40kbd_allocate_port
()))
{
platform_device_unregister
(
q40kbd_device
);
return
-
ENOMEM
;
}
serio_register_port
(
q40kbd_port
);
printk
(
KERN_INFO
"serio: Q40 kbd registered
\n
"
);
...
...
@@ -147,6 +156,7 @@ static int __init q40kbd_init(void)
static
void
__exit
q40kbd_exit
(
void
)
{
serio_unregister_port
(
q40kbd_port
);
platform_device_unregister
(
q40kbd_device
);
}
module_init
(
q40kbd_init
);
...
...
drivers/input/serio/rpckbd.c
View file @
c5ec0513
...
...
@@ -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>
...
...
@@ -45,6 +46,7 @@ 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
)
{
...
...
@@ -119,6 +121,7 @@ static struct serio * __init rpckbd_allocate_port(void)
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
));
}
...
...
@@ -128,8 +131,14 @@ static struct serio * __init rpckbd_allocate_port(void)
static
int
__init
rpckbd_init
(
void
)
{
if
(
!
(
rpckbd_port
=
rpckbd_allocate_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
;
...
...
@@ -138,6 +147,7 @@ static int __init rpckbd_init(void)
static
void
__exit
rpckbd_exit
(
void
)
{
serio_unregister_port
(
rpckbd_port
);
platform_device_unregister
(
rpckbd_device
);
}
module_init
(
rpckbd_init
);
...
...
drivers/input/serio/serio.c
View file @
c5ec0513
...
...
@@ -245,7 +245,6 @@ static ssize_t serio_show_description(struct device *dev, char *buf)
struct
serio
*
serio
=
to_serio_port
(
dev
);
return
sprintf
(
buf
,
"%s
\n
"
,
serio
->
name
);
}
static
DEVICE_ATTR
(
description
,
S_IRUGO
,
serio_show_description
,
NULL
);
static
ssize_t
serio_show_driver
(
struct
device
*
dev
,
char
*
buf
)
{
...
...
@@ -256,7 +255,6 @@ static ssize_t serio_rebind_driver(struct device *dev, const char *buf, size_t c
{
struct
serio
*
serio
=
to_serio_port
(
dev
);
struct
device_driver
*
drv
;
struct
kobject
*
k
;
int
retval
;
retval
=
down_interruptible
(
&
serio_sem
);
...
...
@@ -271,10 +269,10 @@ static ssize_t serio_rebind_driver(struct device *dev, const char *buf, size_t c
}
else
if
(
!
strncmp
(
buf
,
"rescan"
,
count
))
{
serio_disconnect_port
(
serio
);
serio_connect_port
(
serio
,
NULL
);
}
else
if
((
k
=
kset_find_obj
(
&
serio_bus
.
drivers
,
buf
))
!=
NULL
)
{
drv
=
container_of
(
k
,
struct
device_driver
,
kobj
);
}
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
;
}
...
...
@@ -283,7 +281,37 @@ static ssize_t serio_rebind_driver(struct device *dev, const char *buf, size_t c
return
retval
;
}
static
DEVICE_ATTR
(
driver
,
S_IWUSR
|
S_IRUGO
,
serio_show_driver
,
serio_rebind_driver
);
static
ssize_t
serio_show_bind_mode
(
struct
device
*
dev
,
char
*
buf
)
{
struct
serio
*
serio
=
to_serio_port
(
dev
);
return
sprintf
(
buf
,
"%s
\n
"
,
serio
->
manual_bind
?
"manual"
:
"auto"
);
}
static
ssize_t
serio_set_bind_mode
(
struct
device
*
dev
,
const
char
*
buf
,
size_t
count
)
{
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
;
}
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
)
{
...
...
@@ -305,8 +333,6 @@ static void serio_create_port(struct serio *serio)
if
(
serio
->
parent
)
serio
->
dev
.
parent
=
&
serio
->
parent
->
dev
;
device_register
(
&
serio
->
dev
);
device_create_file
(
&
serio
->
dev
,
&
dev_attr_description
);
device_create_file
(
&
serio
->
dev
,
&
dev_attr_driver
);
}
/*
...
...
@@ -350,7 +376,7 @@ static void serio_connect_port(struct serio *serio, struct serio_driver *drv)
if
(
drv
)
serio_bind_driver
(
serio
,
drv
);
else
else
if
(
!
serio
->
manual_bind
)
serio_find_driver
(
serio
);
/* Ok, now bind children, if any */
...
...
@@ -362,6 +388,7 @@ static void serio_connect_port(struct serio *serio, struct serio_driver *drv)
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
...
...
@@ -370,6 +397,7 @@ static void serio_connect_port(struct serio *serio, struct serio_driver *drv)
if
(
!
drv
||
!
serio_bind_driver
(
serio
,
drv
))
serio_find_driver
(
serio
);
}
}
}
/*
...
...
@@ -481,7 +509,37 @@ static ssize_t serio_driver_show_description(struct device_driver *drv, char *bu
struct
serio_driver
*
driver
=
to_serio_driver
(
drv
);
return
sprintf
(
buf
,
"%s
\n
"
,
driver
->
description
?
driver
->
description
:
"(none)"
);
}
static
DRIVER_ATTR
(
description
,
S_IRUGO
,
serio_driver_show_description
,
NULL
);
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"
);
}
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
)
{
...
...
@@ -493,7 +551,6 @@ void serio_register_driver(struct serio_driver *drv)
drv
->
driver
.
bus
=
&
serio_bus
;
driver_register
(
&
drv
->
driver
);
driver_create_file
(
&
drv
->
driver
,
&
driver_attr_description
);
if
(
drv
->
manual_bind
)
goto
out
;
...
...
@@ -541,15 +598,14 @@ void serio_unregister_driver(struct serio_driver *drv)
/* called from serio_driver->connect/disconnect methods under serio_sem */
int
serio_open
(
struct
serio
*
serio
,
struct
serio_driver
*
drv
)
{
unsigned
long
flags
;
spin_lock_irqsave
(
&
serio
->
lock
,
flags
);
serio_pause_rx
(
serio
);
serio
->
drv
=
drv
;
spin_unlock_irqrestore
(
&
serio
->
lock
,
flags
);
serio_continue_rx
(
serio
);
if
(
serio
->
open
&&
serio
->
open
(
serio
))
{
s
pin_lock_irqsave
(
&
serio
->
lock
,
flags
);
s
erio_pause_rx
(
serio
);
serio
->
drv
=
NULL
;
s
pin_unlock_irqrestore
(
&
serio
->
lock
,
flags
);
s
erio_continue_rx
(
serio
);
return
-
1
;
}
return
0
;
...
...
@@ -558,13 +614,12 @@ int serio_open(struct serio *serio, struct serio_driver *drv)
/* called from serio_driver->connect/disconnect methods under serio_sem */
void
serio_close
(
struct
serio
*
serio
)
{
unsigned
long
flags
;
if
(
serio
->
close
)
serio
->
close
(
serio
);
spin_lock_irqsave
(
&
serio
->
lock
,
flags
);
serio_pause_rx
(
serio
);
serio
->
drv
=
NULL
;
s
pin_unlock_irqrestore
(
&
serio
->
lock
,
flags
);
s
erio_continue_rx
(
serio
);
}
irqreturn_t
serio_interrupt
(
struct
serio
*
serio
,
...
...
@@ -599,6 +654,8 @@ static int __init serio_init(void)
return
-
1
;
}
serio_bus
.
dev_attrs
=
serio_device_attrs
;
serio_bus
.
drv_attrs
=
serio_driver_attrs
;
bus_register
(
&
serio_bus
);
return
0
;
...
...
drivers/input/tsdev.c
View file @
c5ec0513
...
...
@@ -210,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
;
...
...
drivers/serial/sunzilog.c
View file @
c5ec0513
...
...
@@ -1529,7 +1529,6 @@ static void __init sunzilog_prepare(void)
static
void
__init
sunzilog_init_kbdms
(
struct
uart_sunzilog_port
*
up
,
int
channel
)
{
int
baud
,
brg
;
struct
serio
*
serio
;
if
(
channel
==
KEYBOARD_LINE
)
{
up
->
flags
|=
SUNZILOG_FLAG_CONS_KEYB
;
...
...
@@ -1546,8 +1545,15 @@ 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
static
void
__init
sunzilog_register_serio
(
struct
uart_sunzilog_port
*
up
,
int
channel
)
{
struct
serio
*
serio
;
up
->
serio
=
serio
=
kmalloc
(
sizeof
(
struct
serio
),
GFP_KERNEL
);
if
(
serio
)
{
...
...
@@ -1576,11 +1582,8 @@ static void __init sunzilog_init_kbdms(struct uart_sunzilog_port *up, int channe
printk
(
KERN_WARNING
"zs%d: not enough memory for serio port
\n
"
,
channel
);
}
#endif
sunzilog_set_mctrl
(
&
up
->
port
,
TIOCM_DTR
|
TIOCM_RTS
);
__sunzilog_startup
(
up
);
}
#endif
static
void
__init
sunzilog_init_hw
(
void
)
{
...
...
@@ -1624,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
}
}
...
...
include/linux/serio.h
View file @
c5ec0513
...
...
@@ -27,6 +27,8 @@ struct serio {
char
name
[
32
];
char
phys
[
32
];
unsigned
int
manual_bind
;
unsigned
short
idbus
;
unsigned
short
idvendor
;
unsigned
short
idproduct
;
...
...
@@ -35,7 +37,7 @@ struct serio {
unsigned
long
type
;
unsigned
long
event
;
spinlock_t
lock
;
spinlock_t
lock
;
/* protects critical sections from port's interrupt handler */
int
(
*
write
)(
struct
serio
*
,
unsigned
char
);
int
(
*
open
)(
struct
serio
*
);
...
...
@@ -43,7 +45,7 @@ struct serio {
struct
serio
*
parent
,
*
child
;
struct
serio_driver
*
drv
;
/* Accessed from interrupt, writes must be protected by serio_
lock */
struct
serio_driver
*
drv
;
/* accessed from interrupt, must be protected by serio->
lock */
struct
device
dev
;
...
...
@@ -55,7 +57,7 @@ struct serio_driver {
void
*
private
;
char
*
description
;
int
manual_bind
;
unsigned
int
manual_bind
;
void
(
*
write_wakeup
)(
struct
serio
*
);
irqreturn_t
(
*
interrupt
)(
struct
serio
*
,
unsigned
char
,
...
...
@@ -81,6 +83,7 @@ void serio_register_port(struct serio *serio);
void
serio_register_port_delayed
(
struct
serio
*
serio
);
void
serio_unregister_port
(
struct
serio
*
serio
);
void
serio_unregister_port_delayed
(
struct
serio
*
serio
);
void
serio_register_driver
(
struct
serio_driver
*
drv
);
void
serio_unregister_driver
(
struct
serio_driver
*
drv
);
...
...
@@ -104,6 +107,22 @@ static __inline__ void serio_cleanup(struct serio *serio)
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