Commit aeef0574 authored by Dmitry Torokhov's avatar Dmitry Torokhov Committed by Vojtech Pavlik

Input: fix race timer handling races in gameport-based joystick drivers

       by moving pollig timer down into gameport and using spinlock to
       protect it.
Signed-off-by: default avatarDmitry Torokhov <dtor@mail.ru>
Signed-off-by: default avatarVojtech Pavlik <vojtech@suse.cz>
parent e9ba1cf0
......@@ -39,6 +39,8 @@ EXPORT_SYMBOL(gameport_rescan);
EXPORT_SYMBOL(gameport_cooked_read);
EXPORT_SYMBOL(gameport_set_name);
EXPORT_SYMBOL(gameport_set_phys);
EXPORT_SYMBOL(gameport_start_polling);
EXPORT_SYMBOL(gameport_stop_polling);
/*
* gameport_sem protects entire gameport subsystem and is taken
......@@ -122,6 +124,37 @@ static int gameport_measure_speed(struct gameport *gameport)
#endif
}
void gameport_start_polling(struct gameport *gameport)
{
spin_lock(&gameport->timer_lock);
if (!gameport->poll_cnt++) {
BUG_ON(!gameport->poll_handler);
BUG_ON(!gameport->poll_interval);
mod_timer(&gameport->poll_timer, jiffies + msecs_to_jiffies(gameport->poll_interval));
}
spin_unlock(&gameport->timer_lock);
}
void gameport_stop_polling(struct gameport *gameport)
{
spin_lock(&gameport->timer_lock);
if (!--gameport->poll_cnt)
del_timer(&gameport->poll_timer);
spin_unlock(&gameport->timer_lock);
}
static void gameport_run_poll_handler(unsigned long d)
{
struct gameport *gameport = (struct gameport *)d;
gameport->poll_handler(gameport);
if (gameport->poll_cnt)
mod_timer(&gameport->poll_timer, jiffies + msecs_to_jiffies(gameport->poll_interval));
}
/*
* Basic gameport -> driver core mappings
......@@ -465,10 +498,14 @@ static void gameport_init_port(struct gameport *gameport)
device_initialize(&gameport->dev);
snprintf(gameport->dev.bus_id, sizeof(gameport->dev.bus_id),
"gameport%lu", (unsigned long)atomic_inc_return(&gameport_no) - 1);
gameport->dev.bus = &gameport_bus;
gameport->dev.release = gameport_release_port;
if (gameport->parent)
gameport->dev.parent = &gameport->parent->dev;
spin_lock_init(&gameport->timer_lock);
init_timer(&gameport->poll_timer);
gameport->poll_timer.function = gameport_run_poll_handler;
gameport->poll_timer.data = (unsigned long)gameport;
}
/*
......@@ -697,6 +734,9 @@ int gameport_open(struct gameport *gameport, struct gameport_driver *drv, int mo
void gameport_close(struct gameport *gameport)
{
del_timer_sync(&gameport->poll_timer);
gameport->poll_handler = NULL;
gameport->poll_interval = 0;
gameport_set_drv(gameport, NULL);
if (gameport->close)
gameport->close(gameport);
......
......@@ -45,7 +45,6 @@ MODULE_LICENSE("GPL");
#define A3D_MAX_STROBE 60 /* 40 us */
#define A3D_DELAY_READ 3 /* 3 ms */
#define A3D_MAX_LENGTH 40 /* 40*3 bits */
#define A3D_REFRESH_TIME HZ/50 /* 20 ms */
#define A3D_MODE_A3D 1 /* Assassin 3D */
#define A3D_MODE_PAN 2 /* Panther */
......@@ -59,12 +58,10 @@ struct a3d {
struct gameport *gameport;
struct gameport *adc;
struct input_dev dev;
struct timer_list timer;
int axes[4];
int buttons;
int mode;
int length;
int used;
int reads;
int bads;
char phys[32];
......@@ -178,19 +175,20 @@ static void a3d_read(struct a3d *a3d, unsigned char *data)
/*
* a3d_timer() reads and analyzes A3D joystick data.
* a3d_poll() reads and analyzes A3D joystick data.
*/
static void a3d_timer(unsigned long private)
static void a3d_poll(struct gameport *gameport)
{
struct a3d *a3d = (void *) private;
struct a3d *a3d = gameport_get_drvdata(gameport);
unsigned char data[A3D_MAX_LENGTH];
a3d->reads++;
if (a3d_read_packet(a3d->gameport, a3d->length, data) != a3d->length
|| data[0] != a3d->mode || a3d_csum(data, a3d->length))
a3d->bads++; else a3d_read(a3d, data);
mod_timer(&a3d->timer, jiffies + A3D_REFRESH_TIME);
if (a3d_read_packet(a3d->gameport, a3d->length, data) != a3d->length ||
data[0] != a3d->mode || a3d_csum(data, a3d->length))
a3d->bads++;
else
a3d_read(a3d, data);
}
/*
......@@ -218,10 +216,11 @@ static int a3d_adc_cooked_read(struct gameport *gameport, int *axes, int *button
static int a3d_adc_open(struct gameport *gameport, int mode)
{
struct a3d *a3d = gameport->port_data;
if (mode != GAMEPORT_MODE_COOKED)
return -1;
if (!a3d->used++)
mod_timer(&a3d->timer, jiffies + A3D_REFRESH_TIME);
gameport_start_polling(a3d->gameport);
return 0;
}
......@@ -233,8 +232,7 @@ static void a3d_adc_close(struct gameport *gameport)
{
struct a3d *a3d = gameport->port_data;
if (!--a3d->used)
del_timer(&a3d->timer);
gameport_stop_polling(a3d->gameport);
}
/*
......@@ -245,8 +243,7 @@ static int a3d_open(struct input_dev *dev)
{
struct a3d *a3d = dev->private;
if (!a3d->used++)
mod_timer(&a3d->timer, jiffies + A3D_REFRESH_TIME);
gameport_start_polling(a3d->gameport);
return 0;
}
......@@ -258,8 +255,7 @@ static void a3d_close(struct input_dev *dev)
{
struct a3d *a3d = dev->private;
if (!--a3d->used)
del_timer(&a3d->timer);
gameport_stop_polling(a3d->gameport);
}
/*
......@@ -278,9 +274,6 @@ static int a3d_connect(struct gameport *gameport, struct gameport_driver *drv)
return -ENOMEM;
a3d->gameport = gameport;
init_timer(&a3d->timer);
a3d->timer.data = (long) a3d;
a3d->timer.function = a3d_timer;
gameport_set_drvdata(gameport, a3d);
......@@ -304,6 +297,9 @@ static int a3d_connect(struct gameport *gameport, struct gameport_driver *drv)
goto fail2;
}
gameport_set_poll_handler(gameport, a3d_poll);
gameport_set_poll_interval(gameport, 20);
sprintf(a3d->phys, "%s/input0", gameport->phys);
if (a3d->mode == A3D_MODE_PXL) {
......
......@@ -49,7 +49,6 @@ MODULE_LICENSE("GPL");
#define ADI_MAX_START 200 /* Trigger to packet timeout [200us] */
#define ADI_MAX_STROBE 40 /* Single bit timeout [40us] */
#define ADI_REFRESH_TIME HZ/50 /* How often to poll the joystick [20 ms] */
#define ADI_INIT_DELAY 10 /* Delay after init packet [10ms] */
#define ADI_DATA_DELAY 4 /* Delay after data packet [4ms] */
......@@ -129,11 +128,9 @@ struct adi {
struct adi_port {
struct gameport *gameport;
struct timer_list timer;
struct adi adi[2];
int bad;
int reads;
int used;
};
/*
......@@ -277,15 +274,15 @@ static int adi_read(struct adi_port *port)
}
/*
* adi_timer() repeatedly polls the Logitech joysticks.
* adi_poll() repeatedly polls the Logitech joysticks.
*/
static void adi_timer(unsigned long data)
static void adi_poll(struct gameport *gameport)
{
struct adi_port *port = (void *) data;
struct adi_port *port = gameport_get_drvdata(gameport);
port->bad -= adi_read(port);
port->reads++;
mod_timer(&port->timer, jiffies + ADI_REFRESH_TIME);
}
/*
......@@ -295,8 +292,8 @@ static void adi_timer(unsigned long data)
static int adi_open(struct input_dev *dev)
{
struct adi_port *port = dev->private;
if (!port->used++)
mod_timer(&port->timer, jiffies + ADI_REFRESH_TIME);
gameport_start_polling(port->gameport);
return 0;
}
......@@ -307,8 +304,8 @@ static int adi_open(struct input_dev *dev)
static void adi_close(struct input_dev *dev)
{
struct adi_port *port = dev->private;
if (!--port->used)
del_timer(&port->timer);
gameport_stop_polling(port->gameport);
}
/*
......@@ -475,9 +472,6 @@ static int adi_connect(struct gameport *gameport, struct gameport_driver *drv)
return -ENOMEM;
port->gameport = gameport;
init_timer(&port->timer);
port->timer.data = (long) port;
port->timer.function = adi_timer;
gameport_set_drvdata(gameport, port);
......@@ -504,6 +498,9 @@ static int adi_connect(struct gameport *gameport, struct gameport_driver *drv)
return -ENODEV;
}
gameport_set_poll_handler(gameport, adi_poll);
gameport_set_poll_interval(gameport, 20);
msleep(ADI_INIT_DELAY);
if (adi_read(port)) {
msleep(ADI_DATA_DELAY);
......
......@@ -90,7 +90,6 @@ __obsolete_setup("js=");
#define ANALOG_MAX_TIME 3 /* 3 ms */
#define ANALOG_LOOP_TIME 2000 /* 2 * loop */
#define ANALOG_REFRESH_TIME HZ/100 /* 10 ms */
#define ANALOG_SAITEK_DELAY 200 /* 200 us */
#define ANALOG_SAITEK_TIME 2000 /* 2000 us */
#define ANALOG_AXIS_TIME 2 /* 2 * refresh */
......@@ -121,7 +120,6 @@ struct analog {
struct analog_port {
struct gameport *gameport;
struct timer_list timer;
struct analog analog[2];
unsigned char mask;
char saitek;
......@@ -134,7 +132,6 @@ struct analog_port {
int axes[4];
int buttons;
int initial[4];
int used;
int axtime;
};
......@@ -307,12 +304,12 @@ static int analog_button_read(struct analog_port *port, char saitek, char chf)
}
/*
* analog_timer() repeatedly polls the Analog joysticks.
* analog_poll() repeatedly polls the Analog joysticks.
*/
static void analog_timer(unsigned long data)
static void analog_poll(struct gameport *gameport)
{
struct analog_port *port = (void *) data;
struct analog_port *port = gameport_get_drvdata(gameport);
int i;
char saitek = !!(port->analog[0].mask & ANALOG_SAITEK);
......@@ -338,8 +335,6 @@ static void analog_timer(unsigned long data)
for (i = 0; i < 2; i++)
if (port->analog[i].mask)
analog_decode(port->analog + i, port->axes, port->initial, port->buttons);
mod_timer(&port->timer, jiffies + ANALOG_REFRESH_TIME);
}
/*
......@@ -349,8 +344,8 @@ static void analog_timer(unsigned long data)
static int analog_open(struct input_dev *dev)
{
struct analog_port *port = dev->private;
if (!port->used++)
mod_timer(&port->timer, jiffies + ANALOG_REFRESH_TIME);
gameport_start_polling(port->gameport);
return 0;
}
......@@ -361,8 +356,8 @@ static int analog_open(struct input_dev *dev)
static void analog_close(struct input_dev *dev)
{
struct analog_port *port = dev->private;
if (!--port->used)
del_timer(&port->timer);
gameport_stop_polling(port->gameport);
}
/*
......@@ -594,9 +589,6 @@ static int analog_init_port(struct gameport *gameport, struct gameport_driver *d
int i, t, u, v;
port->gameport = gameport;
init_timer(&port->timer);
port->timer.data = (long) port;
port->timer.function = analog_timer;
gameport_set_drvdata(gameport, port);
......@@ -678,6 +670,9 @@ static int analog_connect(struct gameport *gameport, struct gameport_driver *drv
return err;
}
gameport_set_poll_handler(gameport, analog_poll);
gameport_set_poll_interval(gameport, 10);
for (i = 0; i < 2; i++)
if (port->analog[i].mask)
analog_init_device(port, port->analog + i, i);
......
......@@ -42,7 +42,6 @@ MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
#define COBRA_MAX_STROBE 45 /* 45 us max wait for first strobe */
#define COBRA_REFRESH_TIME HZ/50 /* 20 ms between reads */
#define COBRA_LENGTH 36
static char* cobra_name = "Creative Labs Blaster GamePad Cobra";
......@@ -51,9 +50,7 @@ static int cobra_btn[] = { BTN_START, BTN_SELECT, BTN_TL, BTN_TR, BTN_X, BTN_Y,
struct cobra {
struct gameport *gameport;
struct timer_list timer;
struct input_dev dev[2];
int used;
int reads;
int bads;
unsigned char exists;
......@@ -114,18 +111,19 @@ static unsigned char cobra_read_packet(struct gameport *gameport, unsigned int *
return ret;
}
static void cobra_timer(unsigned long private)
static void cobra_poll(struct gameport *gameport)
{
struct cobra *cobra = (void *) private;
struct cobra *cobra = gameport_get_drvdata(gameport);
struct input_dev *dev;
unsigned int data[2];
int i, j, r;
cobra->reads++;
if ((r = cobra_read_packet(cobra->gameport, data)) != cobra->exists)
if ((r = cobra_read_packet(gameport, data)) != cobra->exists) {
cobra->bads++;
else
return;
}
for (i = 0; i < 2; i++)
if (cobra->exists & r & (1 << i)) {
......@@ -141,23 +139,21 @@ static void cobra_timer(unsigned long private)
input_sync(dev);
}
mod_timer(&cobra->timer, jiffies + COBRA_REFRESH_TIME);
}
static int cobra_open(struct input_dev *dev)
{
struct cobra *cobra = dev->private;
if (!cobra->used++)
mod_timer(&cobra->timer, jiffies + COBRA_REFRESH_TIME);
gameport_start_polling(cobra->gameport);
return 0;
}
static void cobra_close(struct input_dev *dev)
{
struct cobra *cobra = dev->private;
if (!--cobra->used)
del_timer(&cobra->timer);
gameport_stop_polling(cobra->gameport);
}
static int cobra_connect(struct gameport *gameport, struct gameport_driver *drv)
......@@ -171,9 +167,6 @@ static int cobra_connect(struct gameport *gameport, struct gameport_driver *drv)
return -ENOMEM;
cobra->gameport = gameport;
init_timer(&cobra->timer);
cobra->timer.data = (long) cobra;
cobra->timer.function = cobra_timer;
gameport_set_drvdata(gameport, cobra);
......@@ -195,6 +188,9 @@ static int cobra_connect(struct gameport *gameport, struct gameport_driver *drv)
goto fail2;
}
gameport_set_poll_handler(gameport, cobra_poll);
gameport_set_poll_interval(gameport, 20);
for (i = 0; i < 2; i++)
if ((cobra->exists >> i) & 1) {
......
......@@ -46,7 +46,6 @@ MODULE_LICENSE("GPL");
#define GF2K_STROBE 40 /* The time we wait for the first bit [40 us] */
#define GF2K_TIMEOUT 4 /* Wait for everything to settle [4 ms] */
#define GF2K_LENGTH 80 /* Max number of triplets in a packet */
#define GF2K_REFRESH HZ/50 /* Time between joystick polls [20 ms] */
/*
* Genius joystick ids ...
......@@ -82,11 +81,9 @@ static short gf2k_seq_digital[] = { 590, 320, 860, 0 };
struct gf2k {
struct gameport *gameport;
struct timer_list timer;
struct input_dev dev;
int reads;
int bads;
int used;
unsigned char id;
unsigned char length;
char phys[32];
......@@ -204,36 +201,35 @@ static void gf2k_read(struct gf2k *gf2k, unsigned char *data)
}
/*
* gf2k_timer() reads and analyzes Genius joystick data.
* gf2k_poll() reads and analyzes Genius joystick data.
*/
static void gf2k_timer(unsigned long private)
static void gf2k_poll(struct gameport *gameport)
{
struct gf2k *gf2k = (void *) private;
struct gf2k *gf2k = gameport_get_drvdata(gameport);
unsigned char data[GF2K_LENGTH];
gf2k->reads++;
if (gf2k_read_packet(gf2k->gameport, gf2k_length[gf2k->id], data) < gf2k_length[gf2k->id]) {
if (gf2k_read_packet(gf2k->gameport, gf2k_length[gf2k->id], data) < gf2k_length[gf2k->id])
gf2k->bads++;
} else gf2k_read(gf2k, data);
mod_timer(&gf2k->timer, jiffies + GF2K_REFRESH);
else
gf2k_read(gf2k, data);
}
static int gf2k_open(struct input_dev *dev)
{
struct gf2k *gf2k = dev->private;
if (!gf2k->used++)
mod_timer(&gf2k->timer, jiffies + GF2K_REFRESH);
gameport_start_polling(gf2k->gameport);
return 0;
}
static void gf2k_close(struct input_dev *dev)
{
struct gf2k *gf2k = dev->private;
if (!--gf2k->used)
del_timer(&gf2k->timer);
gameport_stop_polling(gf2k->gameport);
}
/*
......@@ -250,9 +246,6 @@ static int gf2k_connect(struct gameport *gameport, struct gameport_driver *drv)
return -ENOMEM;
gf2k->gameport = gameport;
init_timer(&gf2k->timer);
gf2k->timer.data = (long) gf2k;
gf2k->timer.function = gf2k_timer;
gameport_set_drvdata(gameport, gf2k);
......@@ -295,6 +288,9 @@ static int gf2k_connect(struct gameport *gameport, struct gameport_driver *drv)
goto fail2;
}
gameport_set_poll_handler(gameport, gf2k_poll);
gameport_set_poll_interval(gameport, 20);
sprintf(gf2k->phys, "%s/input0", gameport->phys);
gf2k->length = gf2k_lens[gf2k->id];
......
......@@ -53,14 +53,10 @@ MODULE_LICENSE("GPL");
#define GRIP_MAX_CHUNKS_XT 10
#define GRIP_MAX_BITS_XT 30
#define GRIP_REFRESH_TIME HZ/50 /* 20 ms */
struct grip {
struct gameport *gameport;
struct timer_list timer;
struct input_dev dev[2];
unsigned char mode[2];
int used;
int reads;
int bads;
char phys[2][32];
......@@ -185,9 +181,9 @@ static int grip_xt_read_packet(struct gameport *gameport, int shift, unsigned in
* grip_timer() repeatedly polls the joysticks and generates events.
*/
static void grip_timer(unsigned long private)
static void grip_poll(struct gameport *gameport)
{
struct grip *grip = (void*) private;
struct grip *grip = gameport_get_drvdata(gameport);
unsigned int data[GRIP_LENGTH_XT];
struct input_dev *dev;
int i, j;
......@@ -281,23 +277,21 @@ static void grip_timer(unsigned long private)
input_sync(dev);
}
mod_timer(&grip->timer, jiffies + GRIP_REFRESH_TIME);
}
static int grip_open(struct input_dev *dev)
{
struct grip *grip = dev->private;
if (!grip->used++)
mod_timer(&grip->timer, jiffies + GRIP_REFRESH_TIME);
gameport_start_polling(grip->gameport);
return 0;
}
static void grip_close(struct input_dev *dev)
{
struct grip *grip = dev->private;
if (!--grip->used)
del_timer(&grip->timer);
gameport_stop_polling(grip->gameport);
}
static int grip_connect(struct gameport *gameport, struct gameport_driver *drv)
......@@ -311,9 +305,6 @@ static int grip_connect(struct gameport *gameport, struct gameport_driver *drv)
return -ENOMEM;
grip->gameport = gameport;
init_timer(&grip->timer);
grip->timer.data = (long) grip;
grip->timer.function = grip_timer;
gameport_set_drvdata(gameport, grip);
......@@ -345,6 +336,9 @@ static int grip_connect(struct gameport *gameport, struct gameport_driver *drv)
goto fail2;
}
gameport_set_poll_handler(gameport, grip_poll);
gameport_set_poll_interval(gameport, 20);
for (i = 0; i < 2; i++)
if (grip->mode[i]) {
......
......@@ -38,11 +38,9 @@ MODULE_LICENSE("GPL");
struct grip_mp {
struct gameport *gameport;
struct timer_list timer;
struct input_dev dev[4];
int mode[4];
int registered[4];
int used;
int reads;
int bads;
......@@ -81,7 +79,6 @@ struct grip_mp {
*/
#define GRIP_INIT_DELAY 2000 /* 2 ms */
#define GRIP_REFRESH_TIME HZ/50 /* 20 ms */
#define GRIP_MODE_NONE 0
#define GRIP_MODE_RESET 1
......@@ -526,8 +523,9 @@ static void report_slot(struct grip_mp *grip, int slot)
* Get the multiport state.
*/
static void get_and_report_mp_state(struct grip_mp *grip)
static void grip_poll(struct gameport *gameport)
{
struct grip_mp *grip = gameport_get_drvdata(gameport);
int i, npkts, flags;
for (npkts = 0; npkts < 4; npkts++) {
......@@ -554,8 +552,7 @@ static int grip_open(struct input_dev *dev)
{
struct grip_mp *grip = dev->private;
if (!grip->used++)
mod_timer(&grip->timer, jiffies + GRIP_REFRESH_TIME);
gameport_start_polling(grip->gameport);
return 0;
}
......@@ -567,8 +564,7 @@ static void grip_close(struct input_dev *dev)
{
struct grip_mp *grip = dev->private;
if (!--grip->used)
del_timer(&grip->timer);
gameport_start_polling(grip->gameport);
}
/*
......@@ -606,18 +602,6 @@ static void register_slot(int slot, struct grip_mp *grip)
grip_name[grip->mode[slot]], slot);
}
/*
* Repeatedly polls the multiport and generates events.
*/
static void grip_timer(unsigned long private)
{
struct grip_mp *grip = (void*) private;
get_and_report_mp_state(grip);
mod_timer(&grip->timer, jiffies + GRIP_REFRESH_TIME);
}
static int grip_connect(struct gameport *gameport, struct gameport_driver *drv)
{
struct grip_mp *grip;
......@@ -627,9 +611,6 @@ static int grip_connect(struct gameport *gameport, struct gameport_driver *drv)
return -ENOMEM;
grip->gameport = gameport;
init_timer(&grip->timer);
grip->timer.data = (long) grip;
grip->timer.function = grip_timer;
gameport_set_drvdata(gameport, grip);
......@@ -637,6 +618,9 @@ static int grip_connect(struct gameport *gameport, struct gameport_driver *drv)
if (err)
goto fail1;
gameport_set_poll_handler(gameport, grip_poll);
gameport_set_poll_interval(gameport, 20);
if (!multiport_init(grip)) {
err = -ENODEV;
goto fail2;
......
......@@ -45,7 +45,6 @@ MODULE_LICENSE("GPL");
#define GUILLEMOT_MAX_START 600 /* 600 us */
#define GUILLEMOT_MAX_STROBE 60 /* 60 us */
#define GUILLEMOT_MAX_LENGTH 17 /* 17 bytes */
#define GUILLEMOT_REFRESH_TIME HZ/50 /* 20 ms */
static short guillemot_abs_pad[] =
{ ABS_X, ABS_Y, ABS_THROTTLE, ABS_RUDDER, -1 };
......@@ -69,8 +68,6 @@ struct guillemot_type {
struct guillemot {
struct gameport *gameport;
struct input_dev dev;
struct timer_list timer;
int used;
int bads;
int reads;
struct guillemot_type *type;
......@@ -120,12 +117,12 @@ static int guillemot_read_packet(struct gameport *gameport, u8 *data)
}
/*
* guillemot_timer() reads and analyzes Guillemot joystick data.
* guillemot_poll() reads and analyzes Guillemot joystick data.
*/
static void guillemot_timer(unsigned long private)
static void guillemot_poll(struct gameport *gameport)
{
struct guillemot *guillemot = (struct guillemot *) private;
struct guillemot *guillemot = gameport_get_drvdata(gameport);
struct input_dev *dev = &guillemot->dev;
u8 data[GUILLEMOT_MAX_LENGTH];
int i;
......@@ -150,8 +147,6 @@ static void guillemot_timer(unsigned long private)
}
input_sync(dev);
mod_timer(&guillemot->timer, jiffies + GUILLEMOT_REFRESH_TIME);
}
/*
......@@ -162,8 +157,7 @@ static int guillemot_open(struct input_dev *dev)
{
struct guillemot *guillemot = dev->private;
if (!guillemot->used++)
mod_timer(&guillemot->timer, jiffies + GUILLEMOT_REFRESH_TIME);
gameport_start_polling(guillemot->gameport);
return 0;
}
......@@ -175,8 +169,7 @@ static void guillemot_close(struct input_dev *dev)
{
struct guillemot *guillemot = dev->private;
if (!--guillemot->used)
del_timer(&guillemot->timer);
gameport_stop_polling(guillemot->gameport);
}
/*
......@@ -194,9 +187,6 @@ static int guillemot_connect(struct gameport *gameport, struct gameport_driver *
return -ENOMEM;
guillemot->gameport = gameport;
init_timer(&guillemot->timer);
guillemot->timer.data = (long) guillemot;
guillemot->timer.function = guillemot_timer;
gameport_set_drvdata(gameport, guillemot);
......@@ -222,6 +212,9 @@ static int guillemot_connect(struct gameport *gameport, struct gameport_driver *
goto fail2;
}
gameport_set_poll_handler(gameport, guillemot_poll);
gameport_set_poll_interval(gameport, 20);
sprintf(guillemot->phys, "%s/input0", gameport->phys);
guillemot->type = guillemot_type + i;
......
......@@ -48,7 +48,6 @@ MODULE_LICENSE("GPL");
#define INTERACT_MAX_START 400 /* 400 us */
#define INTERACT_MAX_STROBE 40 /* 40 us */
#define INTERACT_MAX_LENGTH 32 /* 32 bits */
#define INTERACT_REFRESH_TIME HZ/50 /* 20 ms */
#define INTERACT_TYPE_HHFX 0 /* HammerHead/FX */
#define INTERACT_TYPE_PP8D 1 /* ProPad 8 */
......@@ -56,8 +55,6 @@ MODULE_LICENSE("GPL");
struct interact {
struct gameport *gameport;
struct input_dev dev;
struct timer_list timer;
int used;
int bads;
int reads;
unsigned char type;
......@@ -127,12 +124,12 @@ static int interact_read_packet(struct gameport *gameport, int length, u32 *data
}
/*
* interact_timer() reads and analyzes InterAct joystick data.
* interact_poll() reads and analyzes InterAct joystick data.
*/
static void interact_timer(unsigned long private)
static void interact_poll(struct gameport *gameport)
{
struct interact *interact = (struct interact *) private;
struct interact *interact = gameport_get_drvdata(gameport);
struct input_dev *dev = &interact->dev;
u32 data[3];
int i;
......@@ -179,9 +176,6 @@ static void interact_timer(unsigned long private)
}
input_sync(dev);
mod_timer(&interact->timer, jiffies + INTERACT_REFRESH_TIME);
}
/*
......@@ -192,8 +186,7 @@ static int interact_open(struct input_dev *dev)
{
struct interact *interact = dev->private;
if (!interact->used++)
mod_timer(&interact->timer, jiffies + INTERACT_REFRESH_TIME);
gameport_start_polling(interact->gameport);
return 0;
}
......@@ -205,8 +198,7 @@ static void interact_close(struct input_dev *dev)
{
struct interact *interact = dev->private;
if (!--interact->used)
del_timer(&interact->timer);
gameport_stop_polling(interact->gameport);
}
/*
......@@ -224,9 +216,6 @@ static int interact_connect(struct gameport *gameport, struct gameport_driver *d
return -ENOMEM;
interact->gameport = gameport;
init_timer(&interact->timer);
interact->timer.data = (long) interact;
interact->timer.function = interact_timer;
gameport_set_drvdata(gameport, interact);
......@@ -252,6 +241,9 @@ static int interact_connect(struct gameport *gameport, struct gameport_driver *d
goto fail2;
}
gameport_set_poll_handler(gameport, interact_poll);
gameport_set_poll_interval(gameport, 20);
sprintf(interact->phys, "%s/input0", gameport->phys);
interact->type = i;
......
......@@ -48,7 +48,6 @@ MODULE_LICENSE("GPL");
#define TMDC_MAX_START 400 /* 400 us */
#define TMDC_MAX_STROBE 45 /* 45 us */
#define TMDC_MAX_LENGTH 13
#define TMDC_REFRESH_TIME HZ/50 /* 20 ms */
#define TMDC_MODE_M3DI 1
#define TMDC_MODE_3DRP 3
......@@ -94,7 +93,6 @@ static struct {
struct tmdc {
struct gameport *gameport;
struct timer_list timer;
struct input_dev dev[2];
char name[2][64];
char phys[2][32];
......@@ -104,7 +102,6 @@ struct tmdc {
unsigned char absc[2];
unsigned char btnc[2][4];
unsigned char btno[2][4];
int used;
int reads;
int bads;
unsigned char exists;
......@@ -160,13 +157,13 @@ static int tmdc_read_packet(struct gameport *gameport, unsigned char data[2][TMD
}
/*
* tmdc_read() reads and analyzes ThrustMaster joystick data.
* tmdc_poll() reads and analyzes ThrustMaster joystick data.
*/
static void tmdc_timer(unsigned long private)
static void tmdc_poll(struct gameport *gameport)
{
unsigned char data[2][TMDC_MAX_LENGTH];
struct tmdc *tmdc = (void *) private;
struct tmdc *tmdc = gameport_get_drvdata(gameport);
struct input_dev *dev;
unsigned char r, bad = 0;
int i, j, k, l;
......@@ -221,23 +218,21 @@ static void tmdc_timer(unsigned long private)
}
tmdc->bads += bad;
mod_timer(&tmdc->timer, jiffies + TMDC_REFRESH_TIME);
}
static int tmdc_open(struct input_dev *dev)
{
struct tmdc *tmdc = dev->private;
if (!tmdc->used++)
mod_timer(&tmdc->timer, jiffies + TMDC_REFRESH_TIME);
gameport_start_polling(tmdc->gameport);
return 0;
}
static void tmdc_close(struct input_dev *dev)
{
struct tmdc *tmdc = dev->private;
if (!--tmdc->used)
del_timer(&tmdc->timer);
gameport_stop_polling(tmdc->gameport);
}
/*
......@@ -271,9 +266,6 @@ static int tmdc_connect(struct gameport *gameport, struct gameport_driver *drv)
return -ENOMEM;
tmdc->gameport = gameport;
init_timer(&tmdc->timer);
tmdc->timer.data = (long) tmdc;
tmdc->timer.function = tmdc_timer;
gameport_set_drvdata(gameport, tmdc);
......@@ -286,6 +278,9 @@ static int tmdc_connect(struct gameport *gameport, struct gameport_driver *drv)
goto fail2;
}
gameport_set_poll_handler(gameport, tmdc_poll);
gameport_set_poll_interval(gameport, 20);
for (j = 0; j < 2; j++)
if (tmdc->exists & (1 << j)) {
......
......@@ -30,6 +30,12 @@ struct gameport {
int (*open)(struct gameport *, int);
void (*close)(struct gameport *);
struct timer_list poll_timer;
unsigned int poll_interval; /* in msecs */
spinlock_t timer_lock;
unsigned int poll_cnt;
void (*poll_handler)(struct gameport *);
struct gameport *parent, *child;
struct gameport_driver *drv;
......@@ -176,4 +182,17 @@ static inline int gameport_time(struct gameport *gameport, int time)
return (time * gameport->speed) / 1000;
}
static inline void gameport_set_poll_handler(struct gameport *gameport, void (*handler)(struct gameport *))
{
gameport->poll_handler = handler;
}
static inline void gameport_set_poll_interval(struct gameport *gameport, unsigned int msecs)
{
gameport->poll_interval = msecs;
}
void gameport_start_polling(struct gameport *gameport);
void gameport_stop_polling(struct gameport *gameport);
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment