Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
L
linux-davinci
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Redmine
Redmine
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Metrics
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
linux
linux-davinci
Commits
b126207c
Commit
b126207c
authored
Aug 30, 2007
by
Dmitry Torokhov
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Input: joydev - implement proper locking
Signed-off-by:
Dmitry Torokhov
<
dtor@mail.ru
>
parent
464b2415
Changes
1
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
492 additions
and
251 deletions
+492
-251
drivers/input/joydev.c
drivers/input/joydev.c
+492
-251
No files found.
drivers/input/joydev.c
View file @
b126207c
...
...
@@ -43,6 +43,8 @@ struct joydev {
struct
input_handle
handle
;
wait_queue_head_t
wait
;
struct
list_head
client_list
;
spinlock_t
client_lock
;
/* protects client_list */
struct
mutex
mutex
;
struct
device
dev
;
struct
js_corr
corr
[
ABS_MAX
+
1
];
...
...
@@ -61,23 +63,28 @@ struct joydev_client {
int
head
;
int
tail
;
int
startup
;
spinlock_t
buffer_lock
;
/* protects access to buffer, head and tail */
struct
fasync_struct
*
fasync
;
struct
joydev
*
joydev
;
struct
list_head
node
;
};
static
struct
joydev
*
joydev_table
[
JOYDEV_MINORS
];
static
DEFINE_MUTEX
(
joydev_table_mutex
);
static
int
joydev_correct
(
int
value
,
struct
js_corr
*
corr
)
{
switch
(
corr
->
type
)
{
case
JS_CORR_NONE
:
break
;
case
JS_CORR_BROKEN
:
value
=
value
>
corr
->
coef
[
0
]
?
(
value
<
corr
->
coef
[
1
]
?
0
:
((
corr
->
coef
[
3
]
*
(
value
-
corr
->
coef
[
1
]))
>>
14
))
:
((
corr
->
coef
[
2
]
*
(
value
-
corr
->
coef
[
0
]))
>>
14
);
break
;
default:
return
0
;
}
...
...
@@ -85,7 +92,32 @@ static int joydev_correct(int value, struct js_corr *corr)
return
value
<
-
32767
?
-
32767
:
(
value
>
32767
?
32767
:
value
);
}
static
void
joydev_event
(
struct
input_handle
*
handle
,
unsigned
int
type
,
unsigned
int
code
,
int
value
)
static
void
joydev_pass_event
(
struct
joydev_client
*
client
,
struct
js_event
*
event
)
{
struct
joydev
*
joydev
=
client
->
joydev
;
/*
* IRQs already disabled, just acquire the lock
*/
spin_lock
(
&
client
->
buffer_lock
);
client
->
buffer
[
client
->
head
]
=
*
event
;
if
(
client
->
startup
==
joydev
->
nabs
+
joydev
->
nkey
)
{
client
->
head
++
;
client
->
head
&=
JOYDEV_BUFFER_SIZE
-
1
;
if
(
client
->
tail
==
client
->
head
)
client
->
startup
=
0
;
}
spin_unlock
(
&
client
->
buffer_lock
);
kill_fasync
(
&
client
->
fasync
,
SIGIO
,
POLL_IN
);
}
static
void
joydev_event
(
struct
input_handle
*
handle
,
unsigned
int
type
,
unsigned
int
code
,
int
value
)
{
struct
joydev
*
joydev
=
handle
->
private
;
struct
joydev_client
*
client
;
...
...
@@ -104,7 +136,8 @@ static void joydev_event(struct input_handle *handle, unsigned int type, unsigne
case
EV_ABS
:
event
.
type
=
JS_EVENT_AXIS
;
event
.
number
=
joydev
->
absmap
[
code
];
event
.
value
=
joydev_correct
(
value
,
joydev
->
corr
+
event
.
number
);
event
.
value
=
joydev_correct
(
value
,
&
joydev
->
corr
[
event
.
number
]);
if
(
event
.
value
==
joydev
->
abs
[
event
.
number
])
return
;
joydev
->
abs
[
event
.
number
]
=
event
.
value
;
...
...
@@ -116,16 +149,8 @@ static void joydev_event(struct input_handle *handle, unsigned int type, unsigne
event
.
time
=
jiffies_to_msecs
(
jiffies
);
list_for_each_entry
(
client
,
&
joydev
->
client_list
,
node
)
{
memcpy
(
client
->
buffer
+
client
->
head
,
&
event
,
sizeof
(
struct
js_event
));
if
(
client
->
startup
==
joydev
->
nabs
+
joydev
->
nkey
)
if
(
client
->
tail
==
(
client
->
head
=
(
client
->
head
+
1
)
&
(
JOYDEV_BUFFER_SIZE
-
1
)))
client
->
startup
=
0
;
kill_fasync
(
&
client
->
fasync
,
SIGIO
,
POLL_IN
);
}
list_for_each_entry_rcu
(
client
,
&
joydev
->
client_list
,
node
)
joydev_pass_event
(
client
,
&
event
);
wake_up_interruptible
(
&
joydev
->
wait
);
}
...
...
@@ -144,23 +169,85 @@ static void joydev_free(struct device *dev)
{
struct
joydev
*
joydev
=
container_of
(
dev
,
struct
joydev
,
dev
);
joydev_table
[
joydev
->
minor
]
=
NULL
;
kfree
(
joydev
);
}
static
void
joydev_attach_client
(
struct
joydev
*
joydev
,
struct
joydev_client
*
client
)
{
spin_lock
(
&
joydev
->
client_lock
);
list_add_tail_rcu
(
&
client
->
node
,
&
joydev
->
client_list
);
spin_unlock
(
&
joydev
->
client_lock
);
/*
* We don't use synchronize_rcu() here because read-side
* critical section is protected by a spinlock (dev->event_lock)
* instead of rcu_read_lock().
*/
synchronize_sched
();
}
static
void
joydev_detach_client
(
struct
joydev
*
joydev
,
struct
joydev_client
*
client
)
{
spin_lock
(
&
joydev
->
client_lock
);
list_del_rcu
(
&
client
->
node
);
spin_unlock
(
&
joydev
->
client_lock
);
synchronize_sched
();
}
static
int
joydev_open_device
(
struct
joydev
*
joydev
)
{
int
retval
;
retval
=
mutex_lock_interruptible
(
&
joydev
->
mutex
);
if
(
retval
)
return
retval
;
if
(
!
joydev
->
exist
)
retval
=
-
ENODEV
;
else
if
(
!
joydev
->
open
++
)
retval
=
input_open_device
(
&
joydev
->
handle
);
mutex_unlock
(
&
joydev
->
mutex
);
return
retval
;
}
static
void
joydev_close_device
(
struct
joydev
*
joydev
)
{
mutex_lock
(
&
joydev
->
mutex
);
if
(
joydev
->
exist
&&
!--
joydev
->
open
)
input_close_device
(
&
joydev
->
handle
);
mutex_unlock
(
&
joydev
->
mutex
);
}
/*
* Wake up users waiting for IO so they can disconnect from
* dead device.
*/
static
void
joydev_hangup
(
struct
joydev
*
joydev
)
{
struct
joydev_client
*
client
;
spin_lock
(
&
joydev
->
client_lock
);
list_for_each_entry
(
client
,
&
joydev
->
client_list
,
node
)
kill_fasync
(
&
client
->
fasync
,
SIGIO
,
POLL_HUP
);
spin_unlock
(
&
joydev
->
client_lock
);
wake_up_interruptible
(
&
joydev
->
wait
);
}
static
int
joydev_release
(
struct
inode
*
inode
,
struct
file
*
file
)
{
struct
joydev_client
*
client
=
file
->
private_data
;
struct
joydev
*
joydev
=
client
->
joydev
;
joydev_fasync
(
-
1
,
file
,
0
);
list_del
(
&
client
->
node
);
joydev_detach_client
(
joydev
,
client
);
kfree
(
client
);
if
(
!--
joydev
->
open
&&
joydev
->
exist
)
input_close_device
(
&
joydev
->
handle
);
joydev_close_device
(
joydev
);
put_device
(
&
joydev
->
dev
);
return
0
;
...
...
@@ -176,11 +263,16 @@ static int joydev_open(struct inode *inode, struct file *file)
if
(
i
>=
JOYDEV_MINORS
)
return
-
ENODEV
;
error
=
mutex_lock_interruptible
(
&
joydev_table_mutex
);
if
(
error
)
return
error
;
joydev
=
joydev_table
[
i
];
if
(
!
joydev
||
!
joydev
->
exist
)
return
-
ENODEV
;
if
(
joydev
)
get_device
(
&
joydev
->
dev
);
mutex_unlock
(
&
joydev_table_mutex
);
if
(
!
joydev
)
return
-
ENODEV
;
client
=
kzalloc
(
sizeof
(
struct
joydev_client
),
GFP_KERNEL
);
if
(
!
client
)
{
...
...
@@ -188,106 +280,165 @@ static int joydev_open(struct inode *inode, struct file *file)
goto
err_put_joydev
;
}
spin_lock_init
(
&
client
->
buffer_lock
);
client
->
joydev
=
joydev
;
list_add_tail
(
&
client
->
node
,
&
joydev
->
client_lis
t
);
joydev_attach_client
(
joydev
,
clien
t
);
if
(
!
joydev
->
open
++
&&
joydev
->
exist
)
{
error
=
input_open_device
(
&
joydev
->
handle
);
error
=
joydev_open_device
(
joydev
);
if
(
error
)
goto
err_free_client
;
}
file
->
private_data
=
client
;
return
0
;
err_free_client:
list_del
(
&
client
->
node
);
joydev_detach_client
(
joydev
,
client
);
kfree
(
client
);
err_put_joydev:
put_device
(
&
joydev
->
dev
);
return
error
;
}
static
ssize_t
joydev_write
(
struct
file
*
file
,
const
char
__user
*
buffer
,
size_t
count
,
loff_t
*
ppos
)
static
int
joydev_generate_startup_event
(
struct
joydev_client
*
client
,
struct
input_dev
*
input
,
struct
js_event
*
event
)
{
return
-
EINVAL
;
struct
joydev
*
joydev
=
client
->
joydev
;
int
have_event
;
spin_lock_irq
(
&
client
->
buffer_lock
);
have_event
=
client
->
startup
<
joydev
->
nabs
+
joydev
->
nkey
;
if
(
have_event
)
{
event
->
time
=
jiffies_to_msecs
(
jiffies
);
if
(
client
->
startup
<
joydev
->
nkey
)
{
event
->
type
=
JS_EVENT_BUTTON
|
JS_EVENT_INIT
;
event
->
number
=
client
->
startup
;
event
->
value
=
!!
test_bit
(
joydev
->
keypam
[
event
->
number
],
input
->
key
);
}
else
{
event
->
type
=
JS_EVENT_AXIS
|
JS_EVENT_INIT
;
event
->
number
=
client
->
startup
-
joydev
->
nkey
;
event
->
value
=
joydev
->
abs
[
event
->
number
];
}
client
->
startup
++
;
}
spin_unlock_irq
(
&
client
->
buffer_lock
);
return
have_event
;
}
static
ssize_t
joydev_read
(
struct
file
*
file
,
char
__user
*
buf
,
size_t
count
,
loff_t
*
ppos
)
static
int
joydev_fetch_next_event
(
struct
joydev_client
*
client
,
struct
js_event
*
event
)
{
struct
joydev_client
*
client
=
file
->
private_data
;
struct
joydev
*
joydev
=
client
->
joydev
;
struct
input_dev
*
input
=
joydev
->
handle
.
dev
;
int
retval
=
0
;
int
have_event
;
if
(
!
joydev
->
exist
)
return
-
ENODEV
;
spin_lock_irq
(
&
client
->
buffer_lock
);
if
(
count
<
sizeof
(
struct
js_event
))
return
-
EINVAL
;
have_event
=
client
->
head
!=
client
->
tail
;
if
(
have_event
)
{
*
event
=
client
->
buffer
[
client
->
tail
++
];
client
->
tail
&=
JOYDEV_BUFFER_SIZE
-
1
;
}
spin_unlock_irq
(
&
client
->
buffer_lock
);
if
(
count
==
sizeof
(
struct
JS_DATA_TYPE
))
{
return
have_event
;
}
/*
* Old joystick interface
*/
static
ssize_t
joydev_0x_read
(
struct
joydev_client
*
client
,
struct
input_dev
*
input
,
char
__user
*
buf
)
{
struct
joydev
*
joydev
=
client
->
joydev
;
struct
JS_DATA_TYPE
data
;
int
i
;
spin_lock_irq
(
&
input
->
event_lock
);
/*
* Get device state
*/
for
(
data
.
buttons
=
i
=
0
;
i
<
32
&&
i
<
joydev
->
nkey
;
i
++
)
data
.
buttons
|=
test_bit
(
joydev
->
keypam
[
i
],
input
->
key
)
?
(
1
<<
i
)
:
0
;
data
.
buttons
|=
test_bit
(
joydev
->
keypam
[
i
],
input
->
key
)
?
(
1
<<
i
)
:
0
;
data
.
x
=
(
joydev
->
abs
[
0
]
/
256
+
128
)
>>
joydev
->
glue
.
JS_CORR
.
x
;
data
.
y
=
(
joydev
->
abs
[
1
]
/
256
+
128
)
>>
joydev
->
glue
.
JS_CORR
.
y
;
if
(
copy_to_user
(
buf
,
&
data
,
sizeof
(
struct
JS_DATA_TYPE
)))
return
-
EFAULT
;
/*
* Reset reader's event queue
*/
spin_lock
(
&
client
->
buffer_lock
);
client
->
startup
=
0
;
client
->
tail
=
client
->
head
;
spin_unlock
(
&
client
->
buffer_lock
);
spin_unlock_irq
(
&
input
->
event_lock
);
if
(
copy_to_user
(
buf
,
&
data
,
sizeof
(
struct
JS_DATA_TYPE
)))
return
-
EFAULT
;
return
sizeof
(
struct
JS_DATA_TYPE
);
}
}
static
inline
int
joydev_data_pending
(
struct
joydev_client
*
client
)
{
struct
joydev
*
joydev
=
client
->
joydev
;
return
client
->
startup
<
joydev
->
nabs
+
joydev
->
nkey
||
client
->
head
!=
client
->
tail
;
}
if
(
client
->
startup
==
joydev
->
nabs
+
joydev
->
nkey
&&
client
->
head
==
client
->
tail
&&
(
file
->
f_flags
&
O_NONBLOCK
))
static
ssize_t
joydev_read
(
struct
file
*
file
,
char
__user
*
buf
,
size_t
count
,
loff_t
*
ppos
)
{
struct
joydev_client
*
client
=
file
->
private_data
;
struct
joydev
*
joydev
=
client
->
joydev
;
struct
input_dev
*
input
=
joydev
->
handle
.
dev
;
struct
js_event
event
;
int
retval
;
if
(
!
joydev
->
exist
)
return
-
ENODEV
;
if
(
count
<
sizeof
(
struct
js_event
))
return
-
EINVAL
;
if
(
count
==
sizeof
(
struct
JS_DATA_TYPE
))
return
joydev_0x_read
(
client
,
input
,
buf
);
if
(
!
joydev_data_pending
(
client
)
&&
(
file
->
f_flags
&
O_NONBLOCK
))
return
-
EAGAIN
;
retval
=
wait_event_interruptible
(
joydev
->
wait
,
!
joydev
->
exist
||
client
->
startup
<
joydev
->
nabs
+
joydev
->
nkey
||
client
->
head
!=
client
->
tail
);
!
joydev
->
exist
||
joydev_data_pending
(
client
));
if
(
retval
)
return
retval
;
if
(
!
joydev
->
exist
)
return
-
ENODEV
;
while
(
client
->
startup
<
joydev
->
nabs
+
joydev
->
nkey
&&
retval
+
sizeof
(
struct
js_event
)
<=
count
)
{
struct
js_event
event
;
event
.
time
=
jiffies_to_msecs
(
jiffies
);
if
(
client
->
startup
<
joydev
->
nkey
)
{
event
.
type
=
JS_EVENT_BUTTON
|
JS_EVENT_INIT
;
event
.
number
=
client
->
startup
;
event
.
value
=
!!
test_bit
(
joydev
->
keypam
[
event
.
number
],
input
->
key
);
}
else
{
event
.
type
=
JS_EVENT_AXIS
|
JS_EVENT_INIT
;
event
.
number
=
client
->
startup
-
joydev
->
nkey
;
event
.
value
=
joydev
->
abs
[
event
.
number
];
}
while
(
retval
+
sizeof
(
struct
js_event
)
<=
count
&&
joydev_generate_startup_event
(
client
,
input
,
&
event
))
{
if
(
copy_to_user
(
buf
+
retval
,
&
event
,
sizeof
(
struct
js_event
)))
return
-
EFAULT
;
client
->
startup
++
;
retval
+=
sizeof
(
struct
js_event
);
}
while
(
client
->
head
!=
client
->
tail
&&
retval
+
sizeof
(
struct
js_event
)
<=
count
)
{
while
(
retval
+
sizeof
(
struct
js_event
)
<=
count
&&
joydev_fetch_next_event
(
client
,
&
event
))
{
if
(
copy_to_user
(
buf
+
retval
,
client
->
buffer
+
client
->
tail
,
sizeof
(
struct
js_event
)))
if
(
copy_to_user
(
buf
+
retval
,
&
event
,
sizeof
(
struct
js_event
)))
return
-
EFAULT
;
client
->
tail
=
(
client
->
tail
+
1
)
&
(
JOYDEV_BUFFER_SIZE
-
1
);
retval
+=
sizeof
(
struct
js_event
);
}
...
...
@@ -301,11 +452,12 @@ static unsigned int joydev_poll(struct file *file, poll_table *wait)
struct
joydev
*
joydev
=
client
->
joydev
;
poll_wait
(
file
,
&
joydev
->
wait
,
wait
);
return
(
(
client
->
head
!=
client
->
tail
||
client
->
startup
<
joydev
->
nabs
+
joydev
->
nkey
)
?
(
POLLIN
|
POLLRDNORM
)
:
0
)
|
(
joydev
->
exist
?
0
:
(
POLLHUP
|
POLLERR
));
return
(
joydev_data_pending
(
client
)
?
(
POLLIN
|
POLLRDNORM
)
:
0
)
|
(
joydev
->
exist
?
0
:
(
POLLHUP
|
POLLERR
));
}
static
int
joydev_ioctl_common
(
struct
joydev
*
joydev
,
unsigned
int
cmd
,
void
__user
*
argp
)
static
int
joydev_ioctl_common
(
struct
joydev
*
joydev
,
unsigned
int
cmd
,
void
__user
*
argp
)
{
struct
input_dev
*
dev
=
joydev
->
handle
.
dev
;
int
i
,
j
;
...
...
@@ -339,9 +491,11 @@ static int joydev_ioctl_common(struct joydev *joydev, unsigned int cmd, void __u
if
(
copy_from_user
(
joydev
->
corr
,
argp
,
sizeof
(
joydev
->
corr
[
0
])
*
joydev
->
nabs
))
return
-
EFAULT
;
for
(
i
=
0
;
i
<
joydev
->
nabs
;
i
++
)
{
j
=
joydev
->
abspam
[
i
];
joydev
->
abs
[
i
]
=
joydev_correct
(
dev
->
abs
[
j
],
joydev
->
corr
+
i
);
joydev
->
abs
[
i
]
=
joydev_correct
(
dev
->
abs
[
j
],
&
joydev
->
corr
[
i
]);
}
return
0
;
...
...
@@ -350,8 +504,10 @@ static int joydev_ioctl_common(struct joydev *joydev, unsigned int cmd, void __u
sizeof
(
joydev
->
corr
[
0
])
*
joydev
->
nabs
)
?
-
EFAULT
:
0
;
case
JSIOCSAXMAP
:
if
(
copy_from_user
(
joydev
->
abspam
,
argp
,
sizeof
(
__u8
)
*
(
ABS_MAX
+
1
)))
if
(
copy_from_user
(
joydev
->
abspam
,
argp
,
sizeof
(
__u8
)
*
(
ABS_MAX
+
1
)))
return
-
EFAULT
;
for
(
i
=
0
;
i
<
joydev
->
nabs
;
i
++
)
{
if
(
joydev
->
abspam
[
i
]
>
ABS_MAX
)
return
-
EINVAL
;
...
...
@@ -364,13 +520,17 @@ static int joydev_ioctl_common(struct joydev *joydev, unsigned int cmd, void __u
sizeof
(
__u8
)
*
(
ABS_MAX
+
1
))
?
-
EFAULT
:
0
;
case
JSIOCSBTNMAP
:
if
(
copy_from_user
(
joydev
->
keypam
,
argp
,
sizeof
(
__u16
)
*
(
KEY_MAX
-
BTN_MISC
+
1
)))
if
(
copy_from_user
(
joydev
->
keypam
,
argp
,
sizeof
(
__u16
)
*
(
KEY_MAX
-
BTN_MISC
+
1
)))
return
-
EFAULT
;
for
(
i
=
0
;
i
<
joydev
->
nkey
;
i
++
)
{
if
(
joydev
->
keypam
[
i
]
>
KEY_MAX
||
joydev
->
keypam
[
i
]
<
BTN_MISC
)
if
(
joydev
->
keypam
[
i
]
>
KEY_MAX
||
joydev
->
keypam
[
i
]
<
BTN_MISC
)
return
-
EINVAL
;
joydev
->
keymap
[
joydev
->
keypam
[
i
]
-
BTN_MISC
]
=
i
;
}
return
0
;
case
JSIOCGBTNMAP
:
...
...
@@ -378,7 +538,7 @@ static int joydev_ioctl_common(struct joydev *joydev, unsigned int cmd, void __u
sizeof
(
__u16
)
*
(
KEY_MAX
-
BTN_MISC
+
1
))
?
-
EFAULT
:
0
;
default:
if
((
cmd
&
~
(
_IOC_SIZEMASK
<<
_IOC_SIZESHIFT
)
)
==
JSIOCGNAME
(
0
))
{
if
((
cmd
&
~
IOCSIZE_MASK
)
==
JSIOCGNAME
(
0
))
{
int
len
;
if
(
!
dev
->
name
)
return
0
;
...
...
@@ -394,33 +554,42 @@ static int joydev_ioctl_common(struct joydev *joydev, unsigned int cmd, void __u
}
#ifdef CONFIG_COMPAT
static
long
joydev_compat_ioctl
(
struct
file
*
file
,
unsigned
int
cmd
,
unsigned
long
arg
)
static
long
joydev_compat_ioctl
(
struct
file
*
file
,
unsigned
int
cmd
,
unsigned
long
arg
)
{
struct
joydev_client
*
client
=
file
->
private_data
;
struct
joydev
*
joydev
=
client
->
joydev
;
void
__user
*
argp
=
(
void
__user
*
)
arg
;
s32
tmp32
;
struct
JS_DATA_SAVE_TYPE_32
ds32
;
int
err
;
int
retval
;
if
(
!
joydev
->
exist
)
return
-
ENODEV
;
retval
=
mutex_lock_interruptible
(
&
joydev
->
mutex
);
if
(
retval
)
return
retval
;
if
(
!
joydev
->
exist
)
{
retval
=
-
ENODEV
;
goto
out
;
}
switch
(
cmd
)
{
switch
(
cmd
)
{
case
JS_SET_TIMELIMIT
:
err
=
get_user
(
tmp32
,
(
s32
__user
*
)
arg
);
if
(
err
==
0
)
retval
=
get_user
(
tmp32
,
(
s32
__user
*
)
arg
);
if
(
retval
==
0
)
joydev
->
glue
.
JS_TIMELIMIT
=
tmp32
;
break
;
case
JS_GET_TIMELIMIT
:
tmp32
=
joydev
->
glue
.
JS_TIMELIMIT
;
err
=
put_user
(
tmp32
,
(
s32
__user
*
)
arg
);
retval
=
put_user
(
tmp32
,
(
s32
__user
*
)
arg
);
break
;
case
JS_SET_ALL
:
err
=
copy_from_user
(
&
ds32
,
argp
,
retval
=
copy_from_user
(
&
ds32
,
argp
,
sizeof
(
ds32
))
?
-
EFAULT
:
0
;
if
(
err
==
0
)
{
if
(
retval
==
0
)
{
joydev
->
glue
.
JS_TIMEOUT
=
ds32
.
JS_TIMEOUT
;
joydev
->
glue
.
BUSY
=
ds32
.
BUSY
;
joydev
->
glue
.
JS_EXPIRETIME
=
ds32
.
JS_EXPIRETIME
;
...
...
@@ -438,55 +607,119 @@ static long joydev_compat_ioctl(struct file *file, unsigned int cmd, unsigned lo
ds32
.
JS_SAVE
=
joydev
->
glue
.
JS_SAVE
;
ds32
.
JS_CORR
=
joydev
->
glue
.
JS_CORR
;
err
=
copy_to_user
(
argp
,
&
ds32
,
sizeof
(
ds32
))
?
-
EFAULT
:
0
;
retval
=
copy_to_user
(
argp
,
&
ds32
,
sizeof
(
ds32
))
?
-
EFAULT
:
0
;
break
;
default:
err
=
joydev_ioctl_common
(
joydev
,
cmd
,
argp
);
retval
=
joydev_ioctl_common
(
joydev
,
cmd
,
argp
);
break
;
}
return
err
;
out:
mutex_unlock
(
&
joydev
->
mutex
);
return
retval
;
}
#endif
/* CONFIG_COMPAT */
static
int
joydev_ioctl
(
struct
inode
*
inode
,
struct
file
*
file
,
unsigned
int
cmd
,
unsigned
long
arg
)
static
long
joydev_ioctl
(
struct
file
*
file
,
unsigned
int
cmd
,
unsigned
long
arg
)
{
struct
joydev_client
*
client
=
file
->
private_data
;
struct
joydev
*
joydev
=
client
->
joydev
;
void
__user
*
argp
=
(
void
__user
*
)
arg
;
int
retval
;
if
(
!
joydev
->
exist
)
return
-
ENODEV
;
retval
=
mutex_lock_interruptible
(
&
joydev
->
mutex
);
if
(
retval
)
return
retval
;
if
(
!
joydev
->
exist
)
{
retval
=
-
ENODEV
;
goto
out
;
}
switch
(
cmd
)
{
switch
(
cmd
)
{
case
JS_SET_TIMELIMIT
:
return
get_user
(
joydev
->
glue
.
JS_TIMELIMIT
,
(
long
__user
*
)
arg
);
retval
=
get_user
(
joydev
->
glue
.
JS_TIMELIMIT
,
(
long
__user
*
)
arg
);
break
;
case
JS_GET_TIMELIMIT
:
return
put_user
(
joydev
->
glue
.
JS_TIMELIMIT
,
(
long
__user
*
)
arg
);
retval
=
put_user
(
joydev
->
glue
.
JS_TIMELIMIT
,
(
long
__user
*
)
arg
);
break
;
case
JS_SET_ALL
:
return
copy_from_user
(
&
joydev
->
glue
,
argp
,
sizeof
(
joydev
->
glue
))
?
-
EFAULT
:
0
;
retval
=
copy_from_user
(
&
joydev
->
glue
,
argp
,
sizeof
(
joydev
->
glue
))
?
-
EFAULT
:
0
;
break
;
case
JS_GET_ALL
:
return
copy_to_user
(
argp
,
&
joydev
->
glue
,
retval
=
copy_to_user
(
argp
,
&
joydev
->
glue
,
sizeof
(
joydev
->
glue
))
?
-
EFAULT
:
0
;
break
;
default:
return
joydev_ioctl_common
(
joydev
,
cmd
,
argp
);
retval
=
joydev_ioctl_common
(
joydev
,
cmd
,
argp
);
break
;
}
out:
mutex_unlock
(
&
joydev
->
mutex
);
return
retval
;
}
static
const
struct
file_operations
joydev_fops
=
{
.
owner
=
THIS_MODULE
,
.
read
=
joydev_read
,
.
write
=
joydev_write
,
.
poll
=
joydev_poll
,
.
open
=
joydev_open
,
.
release
=
joydev_release
,
.
ioctl
=
joydev_ioctl
,
.
unlocked_ioctl
=
joydev_ioctl
,
#ifdef CONFIG_COMPAT
.
compat_ioctl
=
joydev_compat_ioctl
,
#endif
.
fasync
=
joydev_fasync
,
};
static
int
joydev_install_chrdev
(
struct
joydev
*
joydev
)
{
joydev_table
[
joydev
->
minor
]
=
joydev
;
return
0
;
}
static
void
joydev_remove_chrdev
(
struct
joydev
*
joydev
)
{
mutex_lock
(
&
joydev_table_mutex
);
joydev_table
[
joydev
->
minor
]
=
NULL
;
mutex_unlock
(
&
joydev_table_mutex
);
}
/*
* Mark device non-existant. This disables writes, ioctls and
* prevents new users from opening the device. Already posted
* blocking reads will stay, however new ones will fail.
*/
static
void
joydev_mark_dead
(
struct
joydev
*
joydev
)
{
mutex_lock
(
&
joydev
->
mutex
);
joydev
->
exist
=
0
;
mutex_unlock
(
&
joydev
->
mutex
);
}
static
void
joydev_cleanup
(
struct
joydev
*
joydev
)
{
struct
input_handle
*
handle
=
&
joydev
->
handle
;
joydev_mark_dead
(
joydev
);
joydev_hangup
(
joydev
);
joydev_remove_chrdev
(
joydev
);
/* joydev is marked dead so noone else accesses joydev->open */
if
(
joydev
->
open
)
input_close_device
(
handle
);
}
static
int
joydev_connect
(
struct
input_handler
*
handler
,
struct
input_dev
*
dev
,
const
struct
input_device_id
*
id
)
{
...
...
@@ -494,7 +727,10 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev,
int
i
,
j
,
t
,
minor
;
int
error
;
for
(
minor
=
0
;
minor
<
JOYDEV_MINORS
&&
joydev_table
[
minor
];
minor
++
);
for
(
minor
=
0
;
minor
<
JOYDEV_MINORS
;
minor
++
)
if
(
!
joydev_table
[
minor
])
break
;
if
(
minor
==
JOYDEV_MINORS
)
{
printk
(
KERN_ERR
"joydev: no more free joydev devices
\n
"
);
return
-
ENFILE
;
...
...
@@ -505,15 +741,19 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev,
return
-
ENOMEM
;
INIT_LIST_HEAD
(
&
joydev
->
client_list
);
spin_lock_init
(
&
joydev
->
client_lock
);
mutex_init
(
&
joydev
->
mutex
);
init_waitqueue_head
(
&
joydev
->
wait
);
snprintf
(
joydev
->
name
,
sizeof
(
joydev
->
name
),
"js%d"
,
minor
);
joydev
->
exist
=
1
;
joydev
->
minor
=
minor
;
joydev
->
exist
=
1
;
joydev
->
handle
.
dev
=
dev
;
joydev
->
handle
.
name
=
joydev
->
name
;
joydev
->
handle
.
handler
=
handler
;
joydev
->
handle
.
private
=
joydev
;
snprintf
(
joydev
->
name
,
sizeof
(
joydev
->
name
),
"js%d"
,
minor
);
for
(
i
=
0
;
i
<
ABS_MAX
+
1
;
i
++
)
if
(
test_bit
(
i
,
dev
->
absbit
))
{
...
...
@@ -545,67 +785,65 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev,
}
joydev
->
corr
[
i
].
type
=
JS_CORR_BROKEN
;
joydev
->
corr
[
i
].
prec
=
dev
->
absfuzz
[
j
];
joydev
->
corr
[
i
].
coef
[
0
]
=
(
dev
->
absmax
[
j
]
+
dev
->
absmin
[
j
])
/
2
-
dev
->
absflat
[
j
];
joydev
->
corr
[
i
].
coef
[
1
]
=
(
dev
->
absmax
[
j
]
+
dev
->
absmin
[
j
])
/
2
+
dev
->
absflat
[
j
];
if
(
!
(
t
=
((
dev
->
absmax
[
j
]
-
dev
->
absmin
[
j
])
/
2
-
2
*
dev
->
absflat
[
j
])))
continue
;
joydev
->
corr
[
i
].
coef
[
0
]
=
(
dev
->
absmax
[
j
]
+
dev
->
absmin
[
j
])
/
2
-
dev
->
absflat
[
j
];
joydev
->
corr
[
i
].
coef
[
1
]
=
(
dev
->
absmax
[
j
]
+
dev
->
absmin
[
j
])
/
2
+
dev
->
absflat
[
j
];
t
=
(
dev
->
absmax
[
j
]
-
dev
->
absmin
[
j
])
/
2
-
2
*
dev
->
absflat
[
j
];
if
(
t
)
{
joydev
->
corr
[
i
].
coef
[
2
]
=
(
1
<<
29
)
/
t
;
joydev
->
corr
[
i
].
coef
[
3
]
=
(
1
<<
29
)
/
t
;
joydev
->
abs
[
i
]
=
joydev_correct
(
dev
->
abs
[
j
],
joydev
->
corr
+
i
);
joydev
->
abs
[
i
]
=
joydev_correct
(
dev
->
abs
[
j
],
joydev
->
corr
+
i
);
}
}
s
nprintf
(
joydev
->
dev
.
bus_id
,
sizeof
(
joydev
->
dev
.
bus_id
),
"js%d"
,
minor
);
s
trlcpy
(
joydev
->
dev
.
bus_id
,
joydev
->
name
,
sizeof
(
joydev
->
dev
.
bus_id
));
joydev
->
dev
.
devt
=
MKDEV
(
INPUT_MAJOR
,
JOYDEV_MINOR_BASE
+
minor
);
joydev
->
dev
.
class
=
&
input_class
;
joydev
->
dev
.
parent
=
&
dev
->
dev
;
joydev
->
dev
.
devt
=
MKDEV
(
INPUT_MAJOR
,
JOYDEV_MINOR_BASE
+
minor
);
joydev
->
dev
.
release
=
joydev_free
;
device_initialize
(
&
joydev
->
dev
);
joydev_table
[
minor
]
=
joydev
;
error
=
device_add
(
&
joydev
->
dev
);
error
=
input_register_handle
(
&
joydev
->
handle
);
if
(
error
)
goto
err_free_joydev
;
error
=
input_register_handle
(
&
joydev
->
handle
);
error
=
joydev_install_chrdev
(
joydev
);
if
(
error
)
goto
err_unregister_handle
;
error
=
device_add
(
&
joydev
->
dev
);
if
(
error
)
goto
err_
delete
_joydev
;
goto
err_
cleanup
_joydev
;
return
0
;
err_delete_joydev:
device_del
(
&
joydev
->
dev
);
err_cleanup_joydev:
joydev_cleanup
(
joydev
);
err_unregister_handle:
input_unregister_handle
(
&
joydev
->
handle
);
err_free_joydev:
put_device
(
&
joydev
->
dev
);
return
error
;
}
static
void
joydev_disconnect
(
struct
input_handle
*
handle
)
{
struct
joydev
*
joydev
=
handle
->
private
;
struct
joydev_client
*
client
;
input_unregister_handle
(
handle
);
device_del
(
&
joydev
->
dev
);
joydev
->
exist
=
0
;
if
(
joydev
->
open
)
{
input_close_device
(
handle
);
list_for_each_entry
(
client
,
&
joydev
->
client_list
,
node
)
kill_fasync
(
&
client
->
fasync
,
SIGIO
,
POLL_HUP
);
wake_up_interruptible
(
&
joydev
->
wait
);
}
joydev_cleanup
(
joydev
);
input_unregister_handle
(
handle
);
put_device
(
&
joydev
->
dev
);
}
static
const
struct
input_device_id
joydev_blacklist
[]
=
{
{
.
flags
=
INPUT_DEVICE_ID_MATCH_EVBIT
|
INPUT_DEVICE_ID_MATCH_KEYBIT
,
.
flags
=
INPUT_DEVICE_ID_MATCH_EVBIT
|
INPUT_DEVICE_ID_MATCH_KEYBIT
,
.
evbit
=
{
BIT
(
EV_KEY
)
},
.
keybit
=
{
[
LONG
(
BTN_TOUCH
)]
=
BIT
(
BTN_TOUCH
)
},
},
/* Avoid itouchpads, touchscreens and tablets */
...
...
@@ -614,17 +852,20 @@ static const struct input_device_id joydev_blacklist[] = {
static
const
struct
input_device_id
joydev_ids
[]
=
{
{
.
flags
=
INPUT_DEVICE_ID_MATCH_EVBIT
|
INPUT_DEVICE_ID_MATCH_ABSBIT
,
.
flags
=
INPUT_DEVICE_ID_MATCH_EVBIT
|
INPUT_DEVICE_ID_MATCH_ABSBIT
,
.
evbit
=
{
BIT
(
EV_ABS
)
},
.
absbit
=
{
BIT
(
ABS_X
)
},
},
{
.
flags
=
INPUT_DEVICE_ID_MATCH_EVBIT
|
INPUT_DEVICE_ID_MATCH_ABSBIT
,
.
flags
=
INPUT_DEVICE_ID_MATCH_EVBIT
|
INPUT_DEVICE_ID_MATCH_ABSBIT
,
.
evbit
=
{
BIT
(
EV_ABS
)
},
.
absbit
=
{
BIT
(
ABS_WHEEL
)
},
},
{
.
flags
=
INPUT_DEVICE_ID_MATCH_EVBIT
|
INPUT_DEVICE_ID_MATCH_ABSBIT
,
.
flags
=
INPUT_DEVICE_ID_MATCH_EVBIT
|
INPUT_DEVICE_ID_MATCH_ABSBIT
,
.
evbit
=
{
BIT
(
EV_ABS
)
},
.
absbit
=
{
BIT
(
ABS_THROTTLE
)
},
},
...
...
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