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
805f47cf
Commit
805f47cf
authored
Jul 25, 2002
by
Greg Kroah-Hartman
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
USB: deleted hid-lg3dff.c as it's no longer needed.
parent
97cf4c34
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
0 additions
and
444 deletions
+0
-444
drivers/usb/input/hid-lg3dff.c
drivers/usb/input/hid-lg3dff.c
+0
-444
No files found.
drivers/usb/input/hid-lg3dff.c
deleted
100644 → 0
View file @
97cf4c34
/*
* $$
*
* Force feedback support for hid-compliant devices of the Logitech *3D family
*
* Copyright (c) 2002 Johann Deneux
*/
/*
* 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
* (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 by
* e-mail - mail your message to <deneux@ifrance.com>
*/
#include <linux/input.h>
#include <linux/sched.h>
#define DEBUG
#include <linux/usb.h>
#include <linux/circ_buf.h>
#include "hid.h"
#include "fixp-arith.h"
#define RUN_AT(t) (jiffies + (t))
/* Periodicity of the update */
#define PERIOD (HZ/10)
/* Effect status: lg3d_effect::flags */
#define EFFECT_STARTED 0
/* Effect is going to play after some time
(ff_replay.delay) */
#define EFFECT_PLAYING 1
/* Effect is being played */
#define EFFECT_USED 2
/* Check that the current process can access an effect */
#define CHECK_OWNERSHIP(i, l) \
(i>=0 && i<N_EFFECTS \
&& test_bit(EFFECT_USED, l->effects[i].flags) \
&& (current->pid == 0 \
|| l->effects[i].owner == current->pid))
#define N_EFFECTS 8
struct
lg3d_effect
{
pid_t
owner
;
struct
ff_effect
effect
;
/* Description of the effect */
unsigned
int
count
;
/* Number of times left to play */
unsigned
long
flags
[
1
];
unsigned
long
started_at
;
/* When the effect started to play */
};
// For lg3d_device::flags
#define DEVICE_USB_XMIT 0
/* An URB is being sent */
#define DEVICE_CLOSING 1
/* The driver is being unitialised */
struct
lg3d_device
{
struct
hid_device
*
hid
;
struct
urb
*
urbffout
;
/* Output URB used to send ff commands */
struct
usb_ctrlrequest
ffcr
;
/* ff commands use control URBs */
char
buf
[
8
];
struct
lg3d_effect
effects
[
N_EFFECTS
];
spinlock_t
lock
;
/* device-level lock. Having locks on
a per-effect basis could be nice, but
isn't really necessary */
struct
timer_list
timer
;
unsigned
long
last_time
;
/* Last time the timer handler was
executed */
unsigned
long
flags
[
1
];
/* Contains various information about the
state of the driver for this device */
};
static
void
hid_lg3d_ctrl_out
(
struct
urb
*
urb
);
static
void
hid_lg3d_exit
(
struct
hid_device
*
hid
);
static
int
hid_lg3d_event
(
struct
hid_device
*
hid
,
struct
input_dev
*
input
,
unsigned
int
type
,
unsigned
int
code
,
int
value
);
static
int
hid_lg3d_flush
(
struct
input_dev
*
input
,
struct
file
*
file
);
static
int
hid_lg3d_upload_effect
(
struct
input_dev
*
input
,
struct
ff_effect
*
effect
);
static
int
hid_lg3d_erase
(
struct
input_dev
*
input
,
int
id
);
static
void
hid_lg3d_timer
(
unsigned
long
timer_data
);
int
hid_lg3d_init
(
struct
hid_device
*
hid
)
{
struct
lg3d_device
*
private
;
/* Private data */
private
=
kmalloc
(
sizeof
(
struct
lg3d_device
),
GFP_KERNEL
);
if
(
!
private
)
return
-
1
;
memset
(
private
,
0
,
sizeof
(
struct
lg3d_device
));
hid
->
ff_private
=
private
;
private
->
hid
=
hid
;
spin_lock_init
(
&
private
->
lock
);
/* Timer for the periodic update task */
init_timer
(
&
private
->
timer
);
private
->
timer
.
data
=
(
unsigned
long
)
private
;
private
->
timer
.
function
=
hid_lg3d_timer
;
/* Event and exit callbacks */
hid
->
ff_exit
=
hid_lg3d_exit
;
hid
->
ff_event
=
hid_lg3d_event
;
/* USB init */
if
(
!
(
private
->
urbffout
=
usb_alloc_urb
(
0
,
GFP_KERNEL
)))
{
kfree
(
hid
->
ff_private
);
return
-
1
;
}
usb_fill_control_urb
(
private
->
urbffout
,
hid
->
dev
,
0
,
(
void
*
)
&
private
->
ffcr
,
private
->
buf
,
8
,
hid_lg3d_ctrl_out
,
hid
);
dbg
(
"Created ff output control urb"
);
/* Input init */
hid
->
input
.
upload_effect
=
hid_lg3d_upload_effect
;
hid
->
input
.
flush
=
hid_lg3d_flush
;
set_bit
(
FF_CONSTANT
,
hid
->
input
.
ffbit
);
set_bit
(
EV_FF
,
hid
->
input
.
evbit
);
hid
->
input
.
ff_effects_max
=
N_EFFECTS
;
printk
(
KERN_INFO
"Force feedback for Logitech *3D devices by Johann Deneux <deneux@ifrance.com>
\n
"
);
/* Start the update task */
private
->
timer
.
expires
=
RUN_AT
(
PERIOD
);
add_timer
(
&
private
->
timer
);
/*TODO: only run the timer when at least
one effect is playing */
return
0
;
}
static
void
hid_lg3d_exit
(
struct
hid_device
*
hid
)
{
struct
lg3d_device
*
lg3d
=
hid
->
ff_private
;
unsigned
long
flags
;
spin_lock_irqsave
(
&
lg3d
->
lock
,
flags
);
set_bit
(
DEVICE_CLOSING
,
lg3d
->
flags
);
spin_unlock_irqrestore
(
&
lg3d
->
lock
,
flags
);
del_timer_sync
(
&
lg3d
->
timer
);
if
(
lg3d
->
urbffout
)
{
usb_unlink_urb
(
lg3d
->
urbffout
);
usb_free_urb
(
lg3d
->
urbffout
);
}
kfree
(
lg3d
);
}
static
int
hid_lg3d_event
(
struct
hid_device
*
hid
,
struct
input_dev
*
input
,
unsigned
int
type
,
unsigned
int
code
,
int
value
)
{
struct
lg3d_device
*
lg3d
=
hid
->
ff_private
;
struct
lg3d_effect
*
effect
=
lg3d
->
effects
+
code
;
unsigned
long
flags
;
if
(
type
!=
EV_FF
)
return
-
EINVAL
;
if
(
!
CHECK_OWNERSHIP
(
code
,
lg3d
))
return
-
EACCES
;
if
(
value
<
0
)
return
-
EINVAL
;
spin_lock_irqsave
(
&
lg3d
->
lock
,
flags
);
if
(
value
>
0
)
{
if
(
test_bit
(
EFFECT_STARTED
,
effect
->
flags
))
{
spin_unlock_irqrestore
(
&
lg3d
->
lock
,
flags
);
return
-
EBUSY
;
}
if
(
test_bit
(
EFFECT_PLAYING
,
effect
->
flags
))
{
spin_unlock_irqrestore
(
&
lg3d
->
lock
,
flags
);
return
-
EBUSY
;
}
effect
->
count
=
value
;
if
(
effect
->
effect
.
replay
.
delay
)
{
set_bit
(
EFFECT_STARTED
,
effect
->
flags
);
}
else
{
set_bit
(
EFFECT_PLAYING
,
effect
->
flags
);
}
effect
->
started_at
=
jiffies
;
}
else
{
/* value == 0 */
clear_bit
(
EFFECT_STARTED
,
effect
->
flags
);
clear_bit
(
EFFECT_PLAYING
,
effect
->
flags
);
}
spin_unlock_irqrestore
(
&
lg3d
->
lock
,
flags
);
return
0
;
}
/* Erase all effects this process owns */
static
int
hid_lg3d_flush
(
struct
input_dev
*
dev
,
struct
file
*
file
)
{
struct
hid_device
*
hid
=
dev
->
private
;
struct
lg3d_device
*
lg3d
=
hid
->
ff_private
;
int
i
;
for
(
i
=
0
;
i
<
dev
->
ff_effects_max
;
++
i
)
{
/*NOTE: no need to lock here. The only times EFFECT_USED is
modified is when effects are uploaded or when an effect is
erased. But a process cannot close its dev/input/eventX fd
and perform ioctls on the same fd all at the same time */
if
(
current
->
pid
==
lg3d
->
effects
[
i
].
owner
&&
test_bit
(
EFFECT_USED
,
lg3d
->
effects
[
i
].
flags
))
{
if
(
hid_lg3d_erase
(
dev
,
i
))
warn
(
"erase effect %d failed"
,
i
);
}
}
return
0
;
}
static
int
hid_lg3d_erase
(
struct
input_dev
*
dev
,
int
id
)
{
struct
hid_device
*
hid
=
dev
->
private
;
struct
lg3d_device
*
lg3d
=
hid
->
ff_private
;
unsigned
long
flags
;
if
(
!
CHECK_OWNERSHIP
(
id
,
lg3d
))
return
-
EACCES
;
spin_lock_irqsave
(
&
lg3d
->
lock
,
flags
);
lg3d
->
effects
[
id
].
flags
[
0
]
=
0
;
spin_unlock_irqrestore
(
&
lg3d
->
lock
,
flags
);
return
0
;
}
static
int
hid_lg3d_upload_effect
(
struct
input_dev
*
input
,
struct
ff_effect
*
effect
)
{
struct
hid_device
*
hid
=
input
->
private
;
struct
lg3d_device
*
lg3d
=
hid
->
ff_private
;
struct
lg3d_effect
new
;
int
id
;
unsigned
long
flags
;
dbg
(
"ioctl upload"
);
if
(
!
test_bit
(
effect
->
type
,
input
->
ffbit
))
return
-
EINVAL
;
if
(
effect
->
type
!=
FF_CONSTANT
)
return
-
EINVAL
;
spin_lock_irqsave
(
&
lg3d
->
lock
,
flags
);
if
(
effect
->
id
==
-
1
)
{
int
i
;
for
(
i
=
0
;
i
<
N_EFFECTS
&&
test_bit
(
EFFECT_USED
,
lg3d
->
effects
[
i
].
flags
);
++
i
);
if
(
i
>=
N_EFFECTS
)
{
spin_unlock_irqrestore
(
&
lg3d
->
lock
,
flags
);
return
-
ENOSPC
;
}
effect
->
id
=
i
;
lg3d
->
effects
[
i
].
owner
=
current
->
pid
;
lg3d
->
effects
[
i
].
flags
[
0
]
=
0
;
set_bit
(
EFFECT_USED
,
lg3d
->
effects
[
i
].
flags
);
}
else
if
(
!
CHECK_OWNERSHIP
(
effect
->
id
,
lg3d
))
{
spin_unlock_irqrestore
(
&
lg3d
->
lock
,
flags
);
return
-
EACCES
;
}
id
=
effect
->
id
;
new
=
lg3d
->
effects
[
id
];
new
.
effect
=
*
effect
;
new
.
effect
.
replay
=
effect
->
replay
;
if
(
test_bit
(
EFFECT_STARTED
,
lg3d
->
effects
[
id
].
flags
)
||
test_bit
(
EFFECT_STARTED
,
lg3d
->
effects
[
id
].
flags
))
{
/* Changing replay parameters is not allowed (for the time
being) */
if
(
new
.
effect
.
replay
.
delay
!=
lg3d
->
effects
[
id
].
effect
.
replay
.
delay
||
new
.
effect
.
replay
.
length
!=
lg3d
->
effects
[
id
].
effect
.
replay
.
length
)
{
spin_unlock_irqrestore
(
&
lg3d
->
lock
,
flags
);
return
-
ENOSYS
;
}
lg3d
->
effects
[
id
]
=
new
;
}
else
{
lg3d
->
effects
[
id
]
=
new
;
}
spin_unlock_irqrestore
(
&
lg3d
->
lock
,
flags
);
return
0
;
}
static
void
hid_lg3d_ctrl_out
(
struct
urb
*
urb
)
{
struct
hid_device
*
hid
=
urb
->
context
;
struct
lg3d_device
*
lg3d
=
hid
->
ff_private
;
unsigned
long
flags
;
spin_lock_irqsave
(
&
lg3d
->
lock
,
flags
);
if
(
urb
->
status
)
warn
(
"hid_irq_ffout status %d received"
,
urb
->
status
);
clear_bit
(
DEVICE_USB_XMIT
,
lg3d
->
flags
);
dbg
(
"xmit = 0"
);
spin_unlock_irqrestore
(
&
lg3d
->
lock
,
flags
);
}
static
void
hid_lg3d_timer
(
unsigned
long
timer_data
)
{
struct
lg3d_device
*
lg3d
=
(
struct
lg3d_device
*
)
timer_data
;
struct
hid_device
*
hid
=
lg3d
->
hid
;
unsigned
long
flags
;
int
x
,
y
;
int
i
;
int
err
;
spin_lock_irqsave
(
&
lg3d
->
lock
,
flags
);
if
(
test_bit
(
DEVICE_USB_XMIT
,
lg3d
->
flags
))
{
if
(
lg3d
->
urbffout
->
status
!=
-
EINPROGRESS
)
{
warn
(
"xmit *not* in progress"
);
}
else
{
dbg
(
"xmit in progress"
);
}
spin_unlock_irqrestore
(
&
lg3d
->
lock
,
flags
);
lg3d
->
timer
.
expires
=
RUN_AT
(
PERIOD
);
add_timer
(
&
lg3d
->
timer
);
return
;
}
x
=
0x7f
;
y
=
0x7f
;
for
(
i
=
0
;
i
<
N_EFFECTS
;
++
i
)
{
struct
lg3d_effect
*
effect
=
lg3d
->
effects
+
i
;
if
(
test_bit
(
EFFECT_PLAYING
,
effect
->
flags
))
{
if
(
effect
->
effect
.
type
==
FF_CONSTANT
)
{
//TODO: handle envelopes
int
degrees
=
effect
->
effect
.
direction
*
360
>>
16
;
x
+=
fixp_mult
(
fixp_sin
(
degrees
),
fixp_new16
(
effect
->
effect
.
u
.
constant
.
level
));
y
+=
fixp_mult
(
-
fixp_cos
(
degrees
),
fixp_new16
(
effect
->
effect
.
u
.
constant
.
level
));
}
/* One run of the effect is finished playing */
if
(
time_after
(
jiffies
,
effect
->
started_at
+
effect
->
effect
.
replay
.
delay
*
HZ
/
1000
+
effect
->
effect
.
replay
.
length
*
HZ
/
1000
))
{
dbg
(
"Finished playing once"
);
if
(
--
effect
->
count
<=
0
)
{
dbg
(
"Stopped"
);
clear_bit
(
EFFECT_PLAYING
,
effect
->
flags
);
}
else
{
dbg
(
"Start again"
);
if
(
effect
->
effect
.
replay
.
length
!=
0
)
{
clear_bit
(
EFFECT_PLAYING
,
effect
->
flags
);
set_bit
(
EFFECT_STARTED
,
effect
->
flags
);
}
effect
->
started_at
=
jiffies
;
}
}
}
else
if
(
test_bit
(
EFFECT_STARTED
,
lg3d
->
effects
[
i
].
flags
))
{
dbg
(
"Started"
);
/* Check if we should start playing the effect */
if
(
time_after
(
jiffies
,
lg3d
->
effects
[
i
].
started_at
+
lg3d
->
effects
[
i
].
effect
.
replay
.
delay
*
HZ
/
1000
))
{
dbg
(
"Now playing"
);
clear_bit
(
EFFECT_STARTED
,
lg3d
->
effects
[
i
].
flags
);
set_bit
(
EFFECT_PLAYING
,
lg3d
->
effects
[
i
].
flags
);
}
}
}
if
(
x
<
0
)
x
=
0
;
if
(
x
>
0xff
)
x
=
0xff
;
if
(
y
<
0
)
y
=
0
;
if
(
y
>
0xff
)
y
=
0xff
;
lg3d
->
urbffout
->
pipe
=
usb_sndctrlpipe
(
hid
->
dev
,
0
);
lg3d
->
ffcr
.
bRequestType
=
USB_TYPE_CLASS
|
USB_DIR_OUT
|
USB_RECIP_INTERFACE
;
lg3d
->
urbffout
->
transfer_buffer_length
=
lg3d
->
ffcr
.
wLength
=
8
;
lg3d
->
ffcr
.
bRequest
=
9
;
lg3d
->
ffcr
.
wValue
=
0x0200
;
/*NOTE: Potential problem with
little/big endian */
lg3d
->
ffcr
.
wIndex
=
0
;
lg3d
->
urbffout
->
dev
=
hid
->
dev
;
lg3d
->
buf
[
0
]
=
0x51
;
lg3d
->
buf
[
1
]
=
0x08
;
lg3d
->
buf
[
2
]
=
x
;
lg3d
->
buf
[
3
]
=
y
;
if
((
err
=
usb_submit_urb
(
lg3d
->
urbffout
,
GFP_ATOMIC
)))
warn
(
"usb_submit_urb returned %d"
,
err
);
else
set_bit
(
DEVICE_USB_XMIT
,
lg3d
->
flags
);
if
(
!
test_bit
(
DEVICE_CLOSING
,
lg3d
->
flags
))
{
lg3d
->
timer
.
expires
=
RUN_AT
(
PERIOD
);
add_timer
(
&
lg3d
->
timer
);
}
spin_unlock_irqrestore
(
&
lg3d
->
lock
,
flags
);
}
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